programing

Java/Maven에서 "Xerces hell"을 다루고 있습니까?

prostudy 2022. 7. 24. 21:28
반응형

Java/Maven에서 "Xerces hell"을 다루고 있습니까?

제 사무실에서는, Xerces라는 단어를 언급하는 것만으로도 개발자들의 살인적인 분노를 불러일으키기에 충분합니다.SO에 관한 다른 Xerces 질문을 대충 훑어보면 어느 시점에서 거의 모든 Maven 사용자가 이 문제에 "감동"하고 있음을 알 수 있습니다.불행히도 이 문제를 이해하려면 크세스의 역사에 대한 약간의 지식이 필요합니다.

역사

  • Xerces는 Java 생태계에서 가장 널리 사용되는 XML 파서입니다.Java로 작성된 거의 모든 라이브러리 또는 프레임워크는 일부 용량(직접적이 아닌 경우)에서 Xerces를 사용합니다.

  • 공식 바이너리에 포함된 Xerces 항아리는 현재까지 버전화되어 있지 않습니다.예를 들어 Xerces 2.11.0 구현 jar의 이름은xercesImpl.jar가 아니라xercesImpl-2.11.0.jar.

  • Xerces 은 Maven을 사용하지 않습니다. 즉, Maven Central에 정식 릴리스를 업로드하지 않습니다.

  • Xerces는 이전에는 단일 병으로 출시되었습니다.xerces.jar)는 API를 포함한2개의 항아리로 분할되었습니다.xml-apis.jar및 이러한 API의 구현을 포함하는 것(xercesImpl.jar). 많은 오래된 Maven POM은 여전히 에 의존한다고 선언하고 있습니다.xerces.jar과거 어느 시점에 Xerces는 또한xmlParserAPIs.jar일부 오래된 POM도 이에 의존합니다.

  • Maven 저장소에 xml-apis 및 xercesImpl jar에 할당된 버전이 다른 경우가 많습니다.예를 들어 xml-apis에는 버전 1.3.03, xercesImpl에는 버전 2.8.0을 지정할 수 있습니다.단, 둘 다 Xerces 2.8.0의 것입니다.이는 많은 사람들이 xml-apis jar에 구현된 사양의 버전을 태그하기 때문입니다.여기에는 매우 훌륭하지만 불완전한 내역이 있습니다.

  • Xerces는 JRE에 포함된 Java API for XML Processing(JAXP)의 참조 구현에 사용되는 XML 파서입니다.실장 클래스는 아래 재패키지화 되어 있습니다.com.sun.*네임스페이스는 일부 JRE에서는 사용할 수 없는 경우가 있기 때문에 네임스페이스에 직접 액세스하는 것이 위험합니다.단, Xerces의 일부 기능이java.*그리고.javax.*예를 들어 Xerces 직렬화를 노출하는 API는 없습니다.

  • 게다가 거의 모든 서블릿 컨테이너(JBoss, Jetty, Glassfish, Tomcat 등)는 Xerces와 함께 배송됩니다./lib폴더.

문제

경합 해결

위의 이유 중 일부 또는 모든 이유로 많은 조직이 POM에 Xerces의 커스텀 빌드를 게시하여 사용하고 있습니다.이것은 소규모 애플리케이션을 사용하고 있고 Maven Central만을 사용하고 있는 경우에는 문제가 되지 않지만, Artactory 또는 Nexus가 여러 저장소(JBoss,휴지 상태 등:

xml-apis proxied by Artifactory

예를 들어, 조직 A가 게시할 수 있습니다.xml-apis다음과 같이 합니다.

<groupId>org.apache.xerces</groupId>
<artifactId>xml-apis</artifactId>
<version>2.9.1</version>

한편, 조직 B도 같은 것을 공표할 가능성이 있습니다.jar다음과 같이 합니다.

<groupId>xml-apis</groupId>
<artifactId>xml-apis</artifactId>
<version>1.3.04</version>

B의 것이긴 하지만jarA보다 낮은 버전입니다.jar, Maven은 그들이 다른 것을 가지고 있기 때문에 같은 공예품이라는 것을 알지 못한다.groupIds. 따라서 충돌 해결을 수행할 수 없습니다.jar는 해결된 의존관계로 포함됩니다.

resolved dependencies with multiple xml-apis

클래스 로더 헬

전술한 바와 같이 JRE는 JAXP RI에 Xerces와 함께 출하됩니다.모든 Xerces Maven 종속성을 다음과 같이 표시하면 좋겠지만<exclusion>또는 로서<provided>사용하시는 JDK의 JAXP에서 제공되는 버전에서는 서드파티 코드가 동작하거나 동작하지 않을 수 있습니다.또한 서블릿 컨테이너에 Xerces 항아리도 포함되어 있습니다.이것에 의해, 몇개의 선택지가 남습니다.서블릿 버전을 삭제하고 컨테이너가 JAXP 버전에서 실행되도록 하시겠습니까?서블릿 버전을 그대로 두고 애플리케이션 프레임워크가 서블릿 버전에서 실행되기를 바라는 것이 더 나을까요?위에서 설명한 해결되지 않은 충돌 중 하나 또는 두 개가 제품에 들어가는 경우(대규모 조직에서는 쉽게 일어날 수 있음), 클래스 로더가 런타임에 어떤 버전의 Xerces를 선택하고 있는지, 그리고 Windows와 Linux에서 동일한 jar를 선택할지(아마도 그렇지 않을 수 있음)에 대해 고민하게 됩니다.

솔루션?

Maven 을 "Xerces Maven"으로 <provided> 는는 <exclusion>은 ( 큰에서는) 가명을 있기 에 강제하기 xml-apis,xerces,xercesImpl,xmlParserAPIs서블릿 하는 버전에서는 할 수 .또한 서드파티 libs/framework는 JAXP 버전 또는 서블릿 컨테이너가 제공하는 버전에서는 실행할 수 없습니다.

어떻게 하면 메이븐과 함께 이 문제를 가장 잘 해결할 수 있을까요?의존관계를 이렇게 세밀하게 제어하고 계층화 클래스 로딩에 의존해야 합니까?모든 Xerces 종속성을 글로벌하게 배제하고 모든 프레임워크/libs에서 JAXP 버전을 사용하도록 강제할 수 있는 방법이 있습니까?


업데이트: Joshua Spiewak은 Maven Central에 업로드할 수 있는 Xerces 빌드 스크립트의 패치 버전을 XERCESJ-1454에 업로드했습니다.투표/관람/기부하여 이 문제를 완전히 해결합시다.

2013년 2월 20일 이후 Maven Central에는 2.11.0 JAR(및 소스 JAR!)의 Xerces가 있습니다.Maven Central의 Xerces를 참조하십시오.왜 그들은 https://issues.apache.org/jira/browse/XERCESJ-1454를 해결하지 않았는지 궁금하네요.

사용한 적이 있습니다.

<dependency>
    <groupId>xerces</groupId>
    <artifactId>xercesImpl</artifactId>
    <version>2.11.0</version>
</dependency>

가 잘되었습니다. 의존 관계도 해결되었습니다.xml-apis-1.4.01!

그리고 가장 중요한 것(과거에는 명확하지 않았던 것) - Maven Central의 JAR은 공식 배포와 동일한 JAR입니다.

나는 찾을 수 .xml-schema-1.1-beta- 메이븐 - 수 .classifier-ed ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★」

솔직히 JAXP 버전에서는 거의 모든 것이 정상적으로 동작하기 때문에 항상 제외됩니다. xml-apis ★★★★★★★★★★★★★★★★★」xercesImpl.

금지된 종속성 규칙과 함께 maven 시행기 플러그인을 사용할 수 있습니다.이렇게 하면 원하지 않는 모든 별칭을 금지하고 원하는 별칭만 허용할 수 있습니다.이러한 규칙은 위반 시 프로젝트의 maven build에 실패합니다.또한 이 규칙이 기업의 모든 프로젝트에 적용되는 경우 플러그인 구성을 회사 부모 POM에 넣을 수 있습니다.

참조:

이 질문에 정확히 답변하지 못하는 것은 알지만, 구글에서 온 ppl은 의존관리로 Gradle을 사용하게 됩니다.

Gradle의 모든 xerces/Java8 문제를 이렇게 해결했습니다.

configurations {
    all*.exclude group: 'xml-apis'
    all*.exclude group: 'xerces'
}

당신이 대답해야 할 질문이 하나 있다고 생각합니다.

사용하시는 어플리케이션의 모든 것을 사용할 수 있는 xerces*.jar가 있습니까?

그렇지 않은 경우 기본적으로 문제가 발생하여 동시에 다른 버전의 라이브러리를 로드할 수 있는 OSGI와 같은 것을 사용해야 합니다.기본적으로 jar 버전 문제를 classloader 문제로 대체한다는 점에 유의하시기 바랍니다.

이러한 버전이 있는 경우 저장소에서 모든 종류의 종속성에 대해 해당 버전을 반환하도록 할 수 있습니다.이것은 추악한 해킹으로 클래스 패스에 여러 번 같은 xerces를 실장할 수 있지만, 여러 버전의 xerces를 실장하는 것보다는 낫습니다.

xerces에 대한 모든 종속성을 제외하고 사용하려는 버전에 종속성을 추가할 수 있습니다.

maven의 플러그인으로 버전 해상도 전략을 쓸 수 있는지 궁금합니다.이것은 아마도 가장 좋은 해결책이 될 것입니다만, 가능하다면 조사와 코딩이 필요합니다.

런타임 환경에 포함된 버전의 경우 서버의 lib 폴더가 고려되기 전에 응용 프로그램 클래스 경로에서 제거되거나 응용 프로그램 jar가 먼저 클래스 로딩되도록 고려해야 합니다.

정리하자면:엉망진창이고 그건 변하지 않을 거야.

먼저 디버깅을 수행하여 XML hell 수준을 식별해야 합니다.제 생각에, 첫 번째 단계는 더하는 것입니다.

-Djavax.xml.parsers.SAXParserFactory=com.sun.org.apache.xerces.internal.jaxp.SAXParserFactoryImpl
-Djavax.xml.transform.TransformerFactory=com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl
-Djavax.xml.parsers.DocumentBuilderFactory=com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderFactoryImpl

명령행으로 이동합니다.정상적으로 동작하는 경우는, 라이브러리를 제외합니다.그렇지 않으면 추가합니다.

-Djaxp.debug=1

명령줄로 이동합니다.

여기에서 검토되지 않은 다른 옵션이 있습니다. Maven에서 Xerces 종속성을 옵션으로 선언하는 것입니다.

<dependency>
   <groupId>xerces</groupId>
   <artifactId>xercesImpl</artifactId>
   <version>...</version>
   <optional>true</optional>
</dependency>

기본적으로 모든 의존자가 자신의 Xerces 버전을 선언하도록 강제하지 않으면 프로젝트가 컴파일되지 않습니다.이 의존관계를 덮어쓰려는 경우에는 덮어쓰기를 환영하지만 잠재적인 문제가 발생할 수 있습니다.

이를 통해 다운스트림 프로젝트에 대해 다음과 같은 강력한 인센티브를 얻을 수 있습니다.

  • 적극적으로 결정하다.같은 버전의 Xerces에 대응하고 있습니까, 아니면 다른 것을 사용하고 있습니까?
  • 실제로 해석(예를 들어 유닛 테스트)과 클래스 로딩을 테스트하고 클래스 패스를 복잡하게 만들지 않도록 합니다.

가 새롭게 하는 것은 를 들어, "Dependency"는 다음과 같습니다).mvn dependency:tree이러한 어프로치에 의해, 즉시 그 문제에 주목하게 됩니다.

우리 조직에서는 꽤 효과가 있습니다.그것이 도입되기 전에, 우리는 OP가 묘사하는 것과 같은 지옥에서 살곤 했다.

모든 maven 프로젝트는 xerces에 의존하여 중단되어야 합니다. 아마 실제로 그렇지 않을 것입니다.XML API 및 Imp는 1.4부터 Java의 일부입니다.Java나 Swing에 의존하는 것처럼 xerces나 XML API에 의존할 필요가 없습니다.이것은 암묵적이다.

만약 내가 maven repo의 보스라면, 나는 xerces 의존성을 재귀적으로 제거하는 스크립트를 쓰고, 이 repo에 Java 1.4가 필요하다고 하는 read me를 쓸 것이다.

org.apache Import를 통해 Xerces를 직접 참조하기 때문에 실제로 문제가 발생한 경우 Java 1.4 레벨(2002년 이후 완료)로 업그레이드하기 위한 코드 수정 또는 맵이 아닌 승인된 libs를 통해 JVM 레벨의 솔루션이 필요합니다.

제외를 제외하고 도움이 되는 것은 모듈러 의존성입니다.

플랫 클래스 로드(스탠드 아론 앱) 또는 세미 계층형(JBoss AS/EAP 5.x)에서는 이것이 문제가 되었습니다.

그러나 OSGi 및 JBoss Module과 같은 모듈러 프레임워크에서는 더 이상 큰 문제가 없습니다.도서관은 원하는 도서관을 독립적으로 사용할 수 있습니다.

물론 구현과 버전을 하나만 사용하는 것이 가장 권장되지만, 다른 방법이 없다면(더 많은 libs에서 추가 기능을 사용하는 경우) 모듈화를 통해 비용을 절감할 수 있습니다.

동작하고 있는 JBoss 모듈의 좋은 예로는 당연히 JBoss AS 7 / EAP 6 / WildFly 8이 있습니다.이것들은 주로 JBoss AS 7 / EAP 6 / WildFly 8을 위해 개발되었습니다.

모듈 정의 예:

<?xml version="1.0" encoding="UTF-8"?>
<module xmlns="urn:jboss:module:1.1" name="org.jboss.msc">
    <main-class name="org.jboss.msc.Version"/>
    <properties>
        <property name="my.property" value="foo"/>
    </properties>
    <resources>
        <resource-root path="jboss-msc-1.0.1.GA.jar"/>
    </resources>
    <dependencies>
        <module name="javax.api"/>
        <module name="org.jboss.logging"/>
        <module name="org.jboss.modules"/>
        <!-- Optional deps -->
        <module name="javax.inject.api" optional="true"/>
        <module name="org.jboss.threads" optional="true"/>
    </dependencies>
</module>

OSGi에 비해 JBoss 모듈은 심플하고 고속입니다.특정 기능은 없지만 (대부분) 한 벤더의 관리 하에 있는 대부분의 프로젝트에서 충분하며 (비활성화된 의존관계 해결로 인해) 놀라운 고속 부팅이 가능합니다.

Java 8에서는 모듈화 작업이 진행 중이지만 AFAIK에서는 주로 JRE 자체를 모듈화하는데, 어플리케이션에 적용할 수 있을지는 확실하지 않습니다.

★★★★★★★★★★★★★★.xerces:xml-apis:1.4.01더 이상 중심부에 있지 않다, 하지만xerces:xercesImpl:2.11.0★★★★★★ 。

이것으로 충분합니다.

<dependency>
  <groupId>xerces</groupId>
  <artifactId>xercesImpl</artifactId>
  <version>2.11.0</version>
  <exclusions>
    <exclusion>
      <groupId>xerces</groupId>
      <artifactId>xml-apis</artifactId>
    </exclusion>
  </exclusions>
</dependency>
<dependency>
  <groupId>xml-apis</groupId>
  <artifactId>xml-apis</artifactId>
  <version>1.4.01</version>
</dependency>

내 친구는 매우 간단합니다. 예를 들어,

<dependency>
    <groupId>xalan</groupId>
    <artifactId>xalan</artifactId>
    <version>2.7.2</version>
    <scope>${my-scope}</scope>
    <exclusions>
        <exclusion>
        <groupId>xml-apis</groupId>
        <artifactId>xml-apis</artifactId>
    </exclusion>
</dependency>

또한 단말기(이 예에서는 Windows 콘솔)에서 maven 트리에 문제가 없음을 확인하는 경우:

mvn dependency:tree -Dverbose | grep --color=always '(.* conflict\|^' | less -r

언급URL : https://stackoverflow.com/questions/11677572/dealing-with-xerces-hell-in-java-maven

반응형