누군가의 pom.xml에서 maven-shade-plugin이 사용되고 있음을 발견했습니다. 나는 전에 maven-shade-plugin을 사용한 적이 없으며 (Maven n00b입니다) 이것을 사용하는 이유와 그것이하는 일을 이해하려고했습니다.
나는 Maven docs를 보았지만 이 진술을 이해할 수 없다.
“이 플러그인은 아티팩트를 포함하여 아티팩트를 아군에 패키지하고 일부 종속성의 패키지를 음영 처리 (즉, 이름 바꾸기)하는 기능을 제공합니다.”
페이지의 문서는 초보자에게 친숙하지 않습니다.
“우버 병”이란 무엇입니까? 누군가가 왜 하나를 만들고 싶습니까? 의존성 패키지의 이름을 바꾸는 요점은 무엇입니까? “Uber Jar의 컨텐츠 선택”과 같은 maven-shade-plugin 아파치 페이지의 예제를 살펴 보려고했지만 여전히 “shading”으로 수행중인 작업을 이해할 수 없습니다.
예시적인 예 / 사용 사례 (이 경우 음영이 필요한 이유에 대한 설명과 함께 어떤 문제가 해결되는지에 대한 설명)에 대한 모든 의견을 주시면 감사하겠습니다. 마지막으로 maven-shade-plugin을 언제 사용해야합니까?
답변
간단히 말해 Uber JAR은 모든 것을 포함하는 JAR입니다.
일반적으로 Maven에서는 종속성 관리에 의존합니다. 이슈에는 자체 클래스 / 리소스 만 포함됩니다. Maven은 프로젝트 빌드시기에 따라 프로젝트에있는 모든 아티팩트 (JAR 등)를 찾아야합니다.
동네 짱 항아리는 모든 종속성을 가져 와서 종속성의 내용을 추출하여 프로젝트 자체의 클래스 / 리소스와 함께 하나의 큰 JAR에 넣는 것입니다. 이러한 uber-jar을 사용하면 앱을 실행하기 위해 수많은 작은 JAR 대신 하나의 큰 JAR 만 필요하기 때문에 실행하기 쉽습니다. 경우에 따라 배포가 용이합니다.
단지 참고 사항입니다. Maven의 종속성 해결 기능을 망치므로 uber-jar을 Maven 종속성으로 사용하지 마십시오. 일반적으로 실제 배포 또는 수동 배포를위한 최종 아티팩트에 대해서만 uber-jar을 작성하지만 Maven 저장소에는 넣지 않습니다.
업데이트 : 방금 질문의 한 부분에 대답하지 않았다는 것을 발견했습니다. “종속성의 패키지 이름을 바꾸는 요점은 무엇입니까?” 다음은 간단한 업데이트이며 유사한 질문을 가진 사람들을 도울 것입니다.
쉬운 배포를위한 uber-jar 작성은 쉐도우 플러그인의 사용 사례입니다. 패키지 이름 바꾸기와 관련된 다른 일반적인 사용 사례도 있습니다.
예를 들어, Foo
라이브러리의 특정 버전 (예 : 1.0)에 따라 라이브러리를 개발 중 Bar
입니다. Bar
API 변경 또는 기타 기술적 문제 등으로 인해 다른 버전의 lib를 사용할 수 없다고 가정 합니다. 나는 단순히 선언하는 경우 Bar:1.0
로 Foo
메이븐에의 의존성,이 문제로 분류 할 수 있습니다 :의 Qux
프로젝트에 따라되고 Foo
, 또한 Bar:2.0
(그리고 사용할 수 Bar:1.0
있기 때문에 Qux
필요에 새로운 기능을 사용 Bar:2.0
). 여기에 딜레마는 다음과 같습니다해야 Qux
사용 Bar:1.0
(이 Qux
의 코드는하지 않습니다 작업) 또는 Bar:2.0
( Foo
의 코드가 아닙니다 된 작업이)?
이 문제를 해결하기 위해 개발자 개발자는 Foo
음영 플러그인을 사용하여 사용법의 이름을 바꾸어 jar의 Bar
모든 클래스가 Bar:1.0
jar에 포함되고 Foo
포함 된 Bar
클래스 의 패키지 가에서 com.bar
로 변경 되도록 선택할 수 있습니다 com.foo.bar
. 이렇게하면 더 이상에 의존하지 않기 때문에 Qux
안전하게 의존 할 수 있으며 다른 패키지에있는 “변경된”사본을 사용하고 있습니다.Bar:2.0
Foo
Bar
Bar
답변
나는 최근에 elasticsearch가 왜 (그리고 전부는 아니지만) 그 의존성을 옮기고 있는지 궁금해하고있었습니다. 다음은 프로젝트 관리자 인 @kimchy 의 설명입니다 .
음영 처리 부분은 의도적이며, elasticsearch에서 사용하는 음영 처리 된 라이브러리는 elasticsearch의 모든 의도 및 목적 부분에 사용되며, 사용되는 버전은 elasticsearch가 노출하는 내용 및 라이브러리 작동 방식 (및 내부 작동 방식)을 기반으로 라이브러리를 사용하는 방법에 밀접하게 연결되어 있습니다. 네티와 구아바는 버전 간 변경이 좋은 예입니다.
Btw, 나는 실제로 여러 개의 탄성 검색 병을 제공하는 데 아무런 문제가 없습니다. 하나는 lucene이 음영 처리되지 않은 것이고 다른 하나는 Lucene이 음영 처리되어 있습니다. 그래도 maven으로 어떻게하는지 모르겠습니다. 예를 들어, Elasticsearch가 가지고있는 긴밀한 사용법으로 인해 예를 들어 netty / jackson을 가리지 않는 버전을 제공하고 싶지 않습니다 (예 : 현재 버전을 제외한 이전 버전의 netty에서 곧 버퍼링 개선 사용) 실제로 훨씬 적은 메모리를 사용하는 것과 비교하여 더 많은 메모리를 사용합니다).
-https : //github.com/elasticsearch/elasticsearch/issues/2091#issuecomment-7156766
그리고 drawr의 또 다른 여기 :
쉐이딩은 의존성 (특히 netty, lucene, guava)을 코드와 가깝게 유지하여 업스트림 공급자가 뒤쳐져도 문제를 해결할 수 있도록하는 데 중요합니다. 특정 문제에 도움이되는 모듈화 된 코드 버전을 배포 할 수 있지만 (예 : # 2091) 현재 음영 처리 된 종속성을 제거 할 수는 없습니다. 더 나은 솔루션이 될 때까지 목적에 맞게 로컬 ES 버전을 구축 할 수 있습니다.
-https : //github.com/elasticsearch/elasticsearch/pull/3244#issuecomment-20125452
이것이 하나의 유스 케이스입니다. 예시적인 예를 들어, 다음은 elasticsearch의 pom.xml (v0.90.5)에서 maven-shade-plugin이 사용되는 방법입니다. 이 artifactSet::include
줄은 uber JAR로 가져올 종속성을 지시합니다 (기본적으로 대상 elasticsearch jar이 생성 될 때 elasticsearch의 자체 클래스와 함께 압축이 풀리고 다시 패키지됩니다 (이미 알 수없는 경우 JAR 파일은 프로그램의 클래스, 리소스 등이 포함 된 ZIP 파일과 일부 메타 데이터가 포함되어 있습니다. 파일을 추출하여 구성 방법을 확인할 수 있습니다.)
relocations::relocation
이 경우, 아래를 데려 – 라인은 각각의 경우에 그들은 또한 의존성의 클래스에 지정된 대체를 적용하는 것을 제외하고 유사하다 org.elasticsearch.common
.
마지막 filters
으로이 섹션에서는 대상 메타 데이터, 개미 빌드 파일, 텍스트 파일 등과 같이 종속 항목으로 패키지화되었지만 uber JAR에는 속하지 않는 대상 JAR에서 일부 항목을 제외합니다.
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>2.1</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
</execution>
</executions>
<configuration>
<minimizeJar>true</minimizeJar>
<artifactSet>
<includes>
<include>com.google.guava:guava</include>
<include>net.sf.trove4j:trove4j</include>
<include>org.mvel:mvel2</include>
<include>com.fasterxml.jackson.core:jackson-core</include>
<include>com.fasterxml.jackson.dataformat:jackson-dataformat-smile</include>
<include>com.fasterxml.jackson.dataformat:jackson-dataformat-yaml</include>
<include>joda-time:joda-time</include>
<include>io.netty:netty</include>
<include>com.ning:compress-lzf</include>
</includes>
</artifactSet>
<relocations>
<relocation>
<pattern>com.google.common</pattern>
<shadedPattern>org.elasticsearch.common</shadedPattern>
</relocation>
<relocation>
<pattern>gnu.trove</pattern>
<shadedPattern>org.elasticsearch.common.trove</shadedPattern>
</relocation>
<relocation>
<pattern>jsr166y</pattern>
<shadedPattern>org.elasticsearch.common.util.concurrent.jsr166y</shadedPattern>
</relocation>
<relocation>
<pattern>jsr166e</pattern>
<shadedPattern>org.elasticsearch.common.util.concurrent.jsr166e</shadedPattern>
</relocation>
<relocation>
<pattern>org.mvel2</pattern>
<shadedPattern>org.elasticsearch.common.mvel2</shadedPattern>
</relocation>
<relocation>
<pattern>com.fasterxml.jackson</pattern>
<shadedPattern>org.elasticsearch.common.jackson</shadedPattern>
</relocation>
<relocation>
<pattern>org.joda</pattern>
<shadedPattern>org.elasticsearch.common.joda</shadedPattern>
</relocation>
<relocation>
<pattern>org.jboss.netty</pattern>
<shadedPattern>org.elasticsearch.common.netty</shadedPattern>
</relocation>
<relocation>
<pattern>com.ning.compress</pattern>
<shadedPattern>org.elasticsearch.common.compress</shadedPattern>
</relocation>
</relocations>
<filters>
<filter>
<artifact>*:*</artifact>
<excludes>
<exclude>META-INF/license/**</exclude>
<exclude>META-INF/*</exclude>
<exclude>META-INF/maven/**</exclude>
<exclude>LICENSE</exclude>
<exclude>NOTICE</exclude>
<exclude>/*.txt</exclude>
<exclude>build.properties</exclude>
</excludes>
</filter>
</filters>
</configuration>
</plugin>
</plugins>
답변
작은 경고
비록 선택한 답변이 꽤 잘 설명되어 있기 때문에 maven-shade-plugin을 사용하려는 이유를 설명하지는 않지만 문제가 있음을 알고 싶습니다. JAR이 변경되었으므로 (내가하는 일 때문에) 내 소프트웨어에서 회귀를 일으켰습니다.
따라서이 (또는 maven-jarjar-plugin)를 사용하는 대신 문제없이 작동하는 JarJar의 이진 파일을 사용했습니다.
적절한 솔루션을 찾는 데 시간이 걸리기 때문에 여기에 솔루션을 게시하고 있습니다.
Downlaod JarJar의 JAR 파일
https://code.google.com/p/jarjar/ 에서 항아리를 다운로드 할 수 있습니다
. 왼쪽 메뉴에 다운로드 할 수있는 링크가 있습니다.
한 패키지에서 다른 패키지로 JAR 클래스를 재배치하기 위해 JarJar를 사용하는 방법
이 예에서는 패키지를 “com.fasterxml.jackson”에서 “io.kuku.dependencies.com.fasterxml.jackson”로 변경합니다. -소스 JAR을 “jackson-databind-2.6.4.jar”이라고하고 새로 수정 된 (대상) JAR을 “kuku-jackson-databind-2.6.4.jar”이라고합니다. – “jarjar”JAR 파일은 1.4 버전입니다.
-
“rules.txt”파일을 작성하십시오. 파일의 내용은 다음과 같아야합니다 ( ‘@’문자 앞의 기간을보십시오) : rule com.fasterxml.jackson. ** io.kuku.dependencies.com.fasterxml.jackson. @ 1
-
다음 명령을 실행하십시오. java -jar jarjar-1.4.jar process rules.txt jackson-databind-2.6.4.jar kuku-jackson-databind-2.6.4.jar
로컬 저장소에 수정 된 JAR 설치
이 경우 “c : \ my-jars \”폴더에 3 개의 파일을 설치하고 있습니다.
mvn install : install-file -Dfile = C : \ my-jars \ kuku-jackson-annotations-2.6.4.jar -DgroupId = io.kuku.dependencies -DartifactId = kuku-jackson-annotations -Dversion = 2.6.4- Dpackaging = jar
mvn install : install-file -Dfile = C : \ my-jars \ kuku-jackson-core-2.6.4.jar -DgroupId = io.kuku.dependencies -DartifactId = kuku-jackson-core -Dversion = 2.6.4- Dpackaging = jar
mvn install : install-file -Dfile = C : \ my-jars \ kuku-jackson-databind-2.6.4.jar -DgroupId = io.kuku.dependencies -DartifactId = kuku-jackson-annotations -Dversion = 2.6.4- Dpackaging = jar
프로젝트의 pom에서 수정 된 JAR 사용
이 예에서 프로젝트 pom의 “종속성”요소는 다음과 같습니다.
<dependencies>
<!-- ================================================== -->
<!-- kuku JARs -->
<!-- ================================================== -->
<dependency>
<groupId>io.kuku.dependencies</groupId>
<artifactId>kuku-jackson-annotations</artifactId>
<version>2.6.4</version>
</dependency>
<dependency>
<groupId>io.kuku.dependencies</groupId>
<artifactId>kuku-jackson-core</artifactId>
<version>2.6.4</version>
</dependency>
<dependency>
<groupId>io.kuku.dependencies</groupId>
<artifactId>kuku-jackson-databind</artifactId>
<version>2.6.4</version>
</dependency>
</dependencies>
답변
“음영 처리 된”jar의 필요성에 대한 한 가지 예는 AWS Lambda 함수라고 생각합니다. 그들은 당신이 전형적인 .war 파일에서 찾을 수있는 것처럼 .jars의 전체 컬렉션이 아닌 1 개의 jar 파일 만 업로드 할 수있는 것처럼 보입니다. 따라서 모든 프로젝트 종속성으로 단일 .jar을 작성하면이 작업을 수행 할 수 있습니다.