"음영"Java 종속성이란 무엇입니까?


74

여기에 JVM 개발자가 있습니다. 최근에 나는 IRC 대화방이나 심지어 내 사무실에서도 소위 " 음영 된 "Java 라이브러리에 대한 혼란을 보았습니다 . 사용 컨텍스트는 다음과 같습니다.

" XYZ에"음영이없는 "클라이언트를 제공합니다. "

HBase에 대한이 Jira 문제 는 완벽한 예입니다 . " 음영 처리 된 종속성이있는 클라이언트 아티팩트 게시 "

그래서 나는 묻습니다 : 음영 처리 된 JAR 이 무엇입니까 , "음영 처리되었다"는 것은 무엇을 의미합니까?

답변:


86

쉐이딩 종속성종속성포함하고 이름을 변경 하여 (클래스 재배치 및 영향을받는 바이트 코드 및 리소스 다시 쓰기) 자신의 코드와 함께 번들로 제공되는 개인 복사본만드는 과정 입니다.

이 개념은 일반적으로 동네 짱 (일명 뚱뚱한 항아리 )과 관련이 있습니다.

maven shade plugin 때문에이 용어에 대해 약간의 혼동 이 있습니다.이 단일 이름으로 두 가지 작업을 수행합니다 (자신의 페이지 인용).

이 플러그인은 아티팩트를 포함하여 이슈를 jar에 패키지하고 일부 종속성의 패키지 를 음영 처리 ( 즉, 이름 바꾸기) 하는 기능을 제공합니다 .

따라서 음영 부분은 실제로 선택 사항입니다. 플러그인을 사용하면 항아리 (팻 항아리)에 종속성을 포함하고 선택적으로 이름을 변경 (음영) 합니다.

다른 소스 추가 :

라이브러리를 음영 처리하려면 해당 라이브러리의 컨텐츠 파일을 가져 와서 자신의 항아리에 넣고 패키지를 변경하십시오 . 이것은 라이브러리 파일을 다른 패키지로 옮기지 않고 라이브러리 파일을 자신의 jar 파일로 간단히 전달하는 패키징과 다릅니다.

엄밀히 말하면, 종속성 은 흐리게 표시됩니다. 그러나 뚱뚱한 병목이있는 종속성을 "음영 된 병"이라고하는 것이 일반적이며, 해당 병이 다른 시스템의 클라이언트 인 경우 "음영 클라이언트"라고 할 수 있습니다.

귀하의 질문에 링크 한 HBase에 대한 Jira 문제 의 제목 은 다음과 같습니다 .

음영 처리 된 종속성이있는 클라이언트 아티팩트 게시

그래서이 포스트에서 나는 두 개념을 혼동하지 않고 제시하려고합니다.

좋은

Uber jar는 종종 응용 프로그램을 단일 파일로 제공하는 데 사용됩니다 (배포 및 실행이 쉬워집니다). 또한 종속성의 일부 (또는 전부)와 함께 선박 라이브러리에 사용할 수있는 음영 (이러한 라이브러리의 다른 버전을 사용할 수 있습니다) 다른 응용 프로그램에서 사용할 때 충돌을 방지하기 위해.

uber-jar을 빌드하는 방법에는 여러 가지가 있지만 클래스 재배치 기능 maven-shade-plugin으로 한 단계 더 나아갑니다 .

uber JAR이 다른 프로젝트의 종속성으로 재사용되는 경우 uber JAR에 아티팩트 종속성의 클래스를 직접 포함하면 클래스 경로의 클래스가 중복되어 클래스로드 충돌이 발생할 수 있습니다. 이 문제를 해결하기 위해 음영 처리 된 아티팩트에 포함 된 클래스를 재배치하여 바이트 코드의 개인 복사본을 만들 수 있습니다.

(역사적 주 : Jar Jar Links 는 이전에 재배치 기능을 제공했습니다)

따라서 API에서 해당 라이브러리의 클래스를 공개하지 않는 한 라이브러리 종속성을 구현 세부 사항으로 만들 수 있습니다 .

DecayingSyncQuantanizer클래스 를 제공 하고 Apache commons-rng에 의존 하는 ACME Quantanizer ™ 프로젝트가 있다고 가정 해 봅시다 ( 물론 , 적절하게 양자화하기 위해서는 XorShift1024Star.

쉐이드 메이븐 플러그인을 사용하여 uber-jar을 생성하고 내부를 보면 다음 클래스 파일이 표시됩니다.

com/acme/DecayingSyncQuantanizer.class
org/apache/commons/rng/RandomProviderState.class
org/apache/commons/rng/RestorableUniformRandomProvider.class
...
org/apache/commons/rng/core/source64/XorShift1024Star.class
org/apache/commons/rng/core/util/NumberFactory.class

이제 클래스 재배치 기능을 사용하는 경우 :

<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-shade-plugin</artifactId>
  <version>3.0.0</version>
  <executions>
    <execution>
      <phase>package</phase>
      <goals>
        <goal>shade</goal>
      </goals>
      <configuration>
        <relocations>
          <relocation>
            <pattern>org.apache.commons</pattern>
            <shadedPattern>com.acme.shaded.apachecommons</shadedPattern>
          </relocation>
        </relocations>
      </configuration>
    </execution>
  </executions>
</plugin>

uber-jar의 내용은 다음과 같습니다.

com/acme/DecayingSyncQuantanizer.class
com/acme/shaded/apachecommons/rng/RandomProviderState.class
com/acme/shaded/apachecommons/rng/RestorableUniformRandomProvider.class
...
com/acme/shaded/apachecommons/rng/core/source64/XorShift1024Star.class
com/acme/shaded/apachecommons/rng/core/util/NumberFactory.class

파일 이름을 바꾸는 것이 아니라 재배치 된 클래스를 참조하는 바이트 코드를 다시 작성합니다 (따라서 내 클래스와 commons-rng 클래스가 모두 변환됩니다).

또한 Shade 플러그인은 dependency-reduced-pom.xml음영 처리 된 종속성이 <dependencies>섹션 에서 제거되는 새 POM ( )을 생성합니다 . 이것은 음영 처리 된 jar를 다른 프로젝트의 종속성으로 사용하는 데 도움이됩니다. 따라서 기본 jar 대신 해당 jar을 게시 하거나 둘 다 (음영 된 jar의 한정자를 사용하여) 게시 할 수 있습니다 .

매우 유용 할 수 있습니다 ...

나쁜

... 그러나 그것은 또한 많은 문제를 제기합니다. jar 내에서 모든 종속성을 단일 "네임 스페이스"로 집계하면 지저분해질 수 있으며, 리소스에 대한 음영 및 지저분 함이 필요합니다.

예를 들어 클래스 또는 패키지 이름이 포함 된 리소스 파일을 처리하는 방법은 무엇입니까? 서비스 제공자 디스크립터와 같은 자원 파일은 모두 META-INF/services?

쉐이드 플러그인은 다음과 같은 리소스 변환기 를 제공 합니다 .

여러 아티팩트의 클래스 / 리소스를 하나의 uber JAR로 집계하는 것은 겹치지 않는 한 간단합니다. 그렇지 않으면 여러 JAR에서 자원을 병합하기위한 일종의 논리가 필요합니다. 여기에서 자원 변압기가 시작됩니다.

그러나 여전히 혼란스럽고 문제를 예측하기가 거의 불가능합니다 (생산 과정에서 어려운 문제를 종종 발견합니다). 왜 우리가 멈춘 건물 지방 병을 참조하십시오 .

대체로 뚱뚱한 항아리를 독립 실행 형 앱 / 서비스로 배포하는 것은 여전히 ​​매우 보편적이며 문제를 알고 있어야하며 일부는 음영 이나 다른 트릭 이 필요할 수 있습니다 .

못난이

더 어려운 문제 (디버깅, 테스트 가능성, OSGi 및 이국적인 클래스 로더와의 호환성 ...)가 많이 있습니다.

그러나 더 중요한 것은 라이브러리를 만들 때 독립형 앱 / 서비스로 배포하는 뚱뚱한 항아리와는 달리 항아리가 여러 가지 상황에서 사용될 수 있기 때문에 제어 할 수 있다고 생각한 다양한 문제가 점점 더 복잡해지고 있습니다. 통제 된 환경에서).

예를 들어, ElasticSearch는 배송 된 병의 일부 종속성을 음영 처리하는 데 사용했지만 이를 중지하기로 결정했습니다 .

버전 2.0 이전에는 Elasticsearch가 동일한 아티팩트 내에 음영 처리되고 패키지 된 일부 (전부는 아님) 공통 종속성이있는 JAR로 제공되었습니다. 이를 통해 자체 애플리케이션에 Elasticsearch를 내장 한 Java 사용자는 Guava, Joda, Jackson 등과 같은 모듈의 버전 충돌을 피할 수있었습니다. 물론 여전히 충돌을 일으킬 수있는 Lucene과 같은 음영 처리되지 않은 종속성 목록이 여전히있었습니다.
불행히도, 음영은 복잡하고 오류가 발생하기 쉬운 프로세스로 일부 사람들의 문제는 해결하고 다른 사람들에게는 문제가 발생합니다. 음영 처리를하면 빌드 중에 패키지 이름이 바뀌기 때문에 개발자와 플러그인 작성자가 코드를 올바르게 작성하고 디버그하기가 매우 어렵습니다. 마지막으로, 우리는 음영 처리되지 않은 Elasticsearch를 테스트 한 다음 음영 처리 된 병을 배송했으며 테스트하지 않은 것은 배송하지 않습니다.
2.0 이후부터 쉐이딩하지 않고 Elasticsearch를 제공하기로 결정했습니다.

그것들은 음영 처리 된 항아리가 아닌 음영 처리 된 종속성을 나타냅니다.


1
시간을내어 설명해 주셔서 감사합니다. maven shade plugin의 공식 문서는 완전히 부적절하며 이것에 대해 논의하지도 않고 심지어 "uber jar"를 정의하기도 귀찮습니다. 그 문서는 불분명하고 쓸모가 없습니다. 당신의 쓰기가 유용합니다.
Cheeso

훌륭한 설명입니다. 공식 문서에 포함되어야한다고 생각합니다
Adelin

7

적어도 maven을 사용할 때 음영 처리 된 항아리를 실제로 만드는 소프트웨어의 도움으로 질문에 대답하겠습니다.

으로부터 촬영 아파치 메이븐 그늘 플러그인 홈 페이지 :

이 플러그인은 아티팩트를 포함하여 이슈를 jar에 패키지하고 일부 종속성의 패키지를 음영 처리 (즉, 이름 바꾸기)하는 기능을 제공합니다.

음영 처리 된 항아리 (일명 uber-jar, 일명 팻 항아리)에는 기본적으로 Java 응용 프로그램을 실행하는 데 필요한 모든 종속성이 포함되므로 클래스 경로에 추가 종속성이 필요하지 않습니다. 애플리케이션을 실행하려면 올바른 Java 버전 만 필요합니다. 음영 처리 된 병은 배포 / 클래스 경로 문제를 피하는 데 도움이되지만 원래 응용 프로그램 병보다 훨씬 크며 병을 피하는 데 도움이되지 않습니다.


1
이 답변이 불완전한 것을 두려워하십시오 : 지방 / 우버 항아리가 무엇인지 설명하지만 음영 부분을 설명하지는 않습니다 . 그리고 네, 음영은 "jar hell"(도움말의 마지막 부분을 부정확하게 함)을 돕기 위해 100 %입니다. 그래서 그것은 어느 정도 유용하지만 혼란을 더합니다 :-/
Hugues M.

1
@HuguesMoreau 응답이 100 % 완료되지 않았을 수도 있지만 여전히 내가 원하는 부분을 가져 왔습니다. 누락 된 부품을 테이블로 가져와 주셔서 감사합니다. 음영 처리는 jar 지옥을 피하지 않을 것입니다. 즉, 내가 의미하고 쓴 것이지만, 문제의 일부를 해결할 수는 있지만 자동이 아닌 일부 도구를 제공합니다. 적어도 내가 좋아하는 방식으로 읽고 해석하면 마지막 부분이됩니다. :)
Jesko R.
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.