shade plugin exclude dependency java maven jar maven-shade-plugin

exclude - ¿Para qué se usa el plugin de maven-shade y por qué querría reubicar los paquetes de Java?



maven-shade-plugin (3)

Pequeña advertencia

Aunque eso no describe por qué a uno le gustaría usar el plugin de maven-shade (ya que la respuesta seleccionada lo describe bastante bien), me gustaría señalar que tuve problemas con él. Cambió el JAR (ya que eso es lo que está haciendo) y causó una regresión en mi software.

Entonces, en lugar de usar este (o el plugin maven-jarjar), he usado el binario de JarJar que parece funcionar sin problemas.

Estoy publicando aquí mi solución, ya que me tomó un tiempo encontrar una solución decente.

Archivo JAR de Downlaod JarJar

Puede descargar el archivo jar desde aquí: https://code.google.com/p/jarjar/ En el menú de la izquierda, tiene un enlace para descargarlo.

Cómo usar JarJar para reubicar las clases de un JAR de un paquete a otro

En este ejemplo, cambiaremos el paquete de "com.fasterxml.jackson" a "io.kuku.dependencies.com.fasterxml.jackson". - El JAR de origen se llama "jackson-databind-2.6.4.jar" y el nuevo JAR modificado (objetivo) se llama "kuku-jackson-databind-2.6.4.jar". - El archivo JAR "jarjar" está en la versión 1.4

  1. Crea un archivo "rules.txt". El contenido del archivo debe ser (ver el período antes del carácter ''@''): regla com.fasterxml.jackson. ** io.kuku.dependencies.com.fasterxml.jackson. @ 1

  2. Ejecute el siguiente comando: java -jar jarjar-1.4.jar process rules.txt jackson-databind-2.6.4.jar kuku-jackson-databind-2.6.4.jar

Instalación de los archivos JAR modificados en el repositorio local

En este caso, estoy instalando 3 archivos ubicados en la carpeta "c: / my-jars /".

mvn install: install-file -Dfile = C: / my-jars / kuku-jackson-annotations-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

Usando los JARs modificados en el pom del proyecto.

En este ejemplo, este es el elemento "dependencias" en los proyectos 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>

Encontré el plugin de maven-shade en el pom.xml de alguien. Nunca he usado el plug-in de maven-shade (y soy un Maven n00b), así que traté de entender la razón de usar esto y lo que hace.

Miré los documentos de Maven , sin embargo no puedo entender esta declaración:

"Este complemento proporciona la capacidad de empaquetar el artefacto en un uber-jar, incluidas sus dependencias y sombrear, es decir, renombrar, los paquetes de algunas de las dependencias". La documentación en la página no parece ser muy amigable para los novatos.

¿Qué es un "frasco de uber"? ¿Por qué alguien querría hacer uno? ¿Cuál es el punto de renombrar los paquetes de las dependencias? Traté de leer los ejemplos en la página de apache de plug-in-maven-shade como "Selección de contenido para Uber Jar", pero aún no puedo entender qué se está logrando con "sombreado".

Cualquier indicador de ejemplos ilustrativos / casos de uso (con una explicación de por qué se requiere el sombreado en este caso - qué problema está resolviendo) sería apreciado. Por último, ¿cuándo debo usar el plugin de maven-shade?


Hace poco me preguntaba por qué elástico busca tonos y reubica algunas de sus dependencias (pero no todas). Aquí hay una explicación del @kimchy del proyecto, @kimchy :

La parte de sombreado es intencional, las bibliotecas sombreadas que utilizamos en elasticsearch son para todos los propósitos y la parte de elasticsearch, la versión utilizada está estrechamente relacionada con lo que expone elasticsearch y cómo utiliza la biblioteca según los aspectos internos de cómo funciona la biblioteca (y que cambia entre versiones), netty y guava son grandes ejemplos.

Por cierto, no tengo ningún problema en el hecho de proporcionar varios frascos de elasticsearch, uno con lucene sin sombreado y otro con lucene sombreado. Aunque no estoy seguro de cómo hacerlo con Maven. No quiero proporcionar una versión que no proteja a netty / jackson, por ejemplo, debido al uso profundo que tiene el elasticsearch (por ejemplo, usar la próxima mejora de buffering con cualquier versión anterior de netty, excepto la actual). en realidad usa más memoria en comparación con usar considerablemente menos).

- https://github.com/elasticsearch/elasticsearch/issues/2091#issuecomment-7156766

Y otro aquí de drawr :

El sombreado es importante para mantener nuestras dependencias (especialmente netty, lucene, guava) cerca de nuestro código para que podamos solucionar un problema, incluso si el proveedor ascendente se queda atrás. Es posible que distribuyamos versiones modularizadas del código, lo que ayudaría con su problema particular (# 2091 por ejemplo), pero no podemos simplemente eliminar las dependencias sombreadas en este momento. Puede crear una versión local de ES para sus propósitos hasta que haya una mejor solución.

- https://github.com/elasticsearch/elasticsearch/pull/3244#issuecomment-20125452

Entonces, ese es un caso de uso. En cuanto a un ejemplo ilustrativo, a continuación se muestra cómo se utiliza maven-shade-plugin en pom.xml de elasticsearch (v0.90.5). Las líneas artifactSet::include indican qué dependencias deben ingresar en el JAR de uber (básicamente, se descomprimen y se vuelven a empaquetar junto con las propias clases de elasticsearch cuando se produce el tarro de elasticsearch. (En caso de que no lo sepa ya, un archivo JAR es solo un archivo ZIP que contiene las clases del programa, los recursos, etc., y algunos metadatos. Puede extraer uno para ver cómo están juntos.

Las líneas de relocations::relocation son similares, excepto que en cada caso también aplican las sustituciones especificadas a las clases de la dependencia; en este caso, las org.elasticsearch.common en org.elasticsearch.common .

Finalmente, la sección de filters excluye algunas cosas del JAR de destino que no deberían estar allí, como metadatos de JAR, archivos de compilación de ant., Archivos de texto, etc. que están empaquetados con algunas dependencias, pero que no pertenecen a un JAR de uber. .

<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>


Uber JAR, en definitiva, es un JAR que contiene todo.

Normalmente en Maven, dependemos de la gestión de la dependencia. Un artefacto contiene solo las clases / recursos de si mismo. Maven será responsable de averiguar todos los artefactos (JAR, etc.) que el proyecto dependerá de cuándo se construya el proyecto.

Un uber-jar es algo que toma todas las dependencias, extrae el contenido de las dependencias y las coloca con las clases / recursos del proyecto en sí, en un gran JAR. Al tener este uber-jar, es fácil de ejecutar, ya que solo necesitarás un gran JAR en lugar de toneladas de pequeños JAR para ejecutar tu aplicación. También facilita la distribución en algunos casos.

Sólo una nota al margen. Evite utilizar uber-jar como dependencia de Maven, ya que está arruinando la función de resolución de dependencias de Maven. Normalmente creamos uber-jar solo para el artefacto final para la implementación real o para la distribución manual, pero no para colocar en el repositorio de Maven.

Actualización: Acabo de descubrir que no he respondido a una parte de la pregunta: "¿Cuál es el punto de cambiar el nombre de los paquetes de las dependencias?". Aquí hay algunas actualizaciones breves y esperamos que ayuden a las personas que tienen preguntas similares.

La creación de uber-jar para facilitar la implementación es un caso de uso del complemento de sombra. También hay otros casos de uso comunes que implican renombrar paquetes.

Por ejemplo, estoy desarrollando la biblioteca Foo , que depende de una versión específica (por ejemplo, 1.0) de la biblioteca Bar . Suponiendo que no puedo usar otra versión de Bar lib (debido a un cambio en la API u otros problemas técnicos, etc.). Si simplemente declaro Bar:1.0 como la dependencia de Foo en Maven, es posible caer en un problema: un proyecto de Qux depende de Foo y también de Bar:2.0 (y no puede usar Bar:1.0 porque Qux necesita usar Nueva función en Bar:2.0 ). Aquí está el dilema: ¿ Qux debe usar la Bar:1.0 (que el código de Qux no funcionará) o la Bar:2.0 (que el código de Foo no funcionará)?

Para resolver este problema, el desarrollador de Foo puede optar por usar el complemento de sombra para cambiar el nombre de su uso de Bar , de modo que todas las clases en el jar Bar:1.0 están incrustadas en el jar de Foo , y el paquete de las clases de Bar incrustadas cambia de com.bar a com.foo.bar . Al hacerlo, Qux puede depender con seguridad de Bar:2.0 porque ahora Foo ya no depende de Bar , y está utilizando su propia copia de la Bar "alterada" ubicada en otro paquete.