¿Para qué se utiliza el plugin maven-shade-plugin y por qué quieres reubicar los paquetes Java?

Descubrí que maven-shade-plugin se usaba en el pom.xml de alguien. Nunca he usado maven-shade-plugin antes (y soy un Maven n00b), así que traté de entender la razón por la que usé esto y lo que hace.

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

“Este complemento ofrece la capacidad de empaquetar el artefacto en un uber-jar, incluidas sus dependencias y sombrear, es decir, cambiar el nombre, los paquetes de algunas de las dependencias”. La documentación en la página no parece muy amiga de los novatos.

¿Qué es un “jarra uber”? ¿Por qué alguien querría hacer uno? ¿Cuál es el punto de cambiar el nombre de los paquetes de las dependencias? Traté de ver los ejemplos en la página apache de maven-shade-plugin, como “Seleccionar contenidos para Uber Jar”, pero todavía no puedo entender lo que se está logrando con “sombreado”.

Se agradecerá cualquier sugerencia a ejemplos ilustrativos / casos de uso (con una explicación de por qué se requería sombreado en este caso, qué problema está resolviendo). Por último, ¿cuándo debería usar maven-shade-plugin?

Uber JAR, en resumen, 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 sí mismo. Maven será responsable de descubrir todos los artefactos (JAR, etc.) que el proyecto depende de cuándo se construye el proyecto.

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

Solo una nota al margen. Evite utilizar uber-jar como dependencia de Maven, ya que está arruinando la función de resolución de dependencia 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 el repository de Maven.


Actualización: Acabo de descubrir que no he respondido una parte de la pregunta: “¿De qué sirve cambiar el nombre de los paquetes de las dependencias?”. Aquí hay algunas actualizaciones breves y con suerte ayudarán a las personas a tener preguntas similares.

La creación de uber-jar para facilitar la implementación es un caso de uso del plugin de sombra. También hay otros casos de uso común que implican el cambio de nombre del paquete.

Por ejemplo, estoy desarrollando la biblioteca Foo , que depende de una versión específica (por ejemplo, 1.0) de la biblioteca Bar . Asumiendo que no puedo hacer uso de otra versión de Bar lib (porque el cambio de 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 Qux depende de Foo , y también Bar:2.0 (y no puede usar Bar:1.0 porque Qux necesita usarlo). nueva característica en Bar:2.0 ). Aquí está el dilema: ¿Debería Qux usar Bar:1.0 (que el código de Qux no funcionará) o Bar:2.0 (cuyo código de Foo no funcionará)?

Para resolver este problema, el desarrollador de Foo puede elegir usar el plugin de sombra para cambiar el nombre de su uso de Bar , de modo que todas las clases en Bar:1.0 jar estén incrustadas en el jar de Foo , y el paquete de las clases de Bar incorporadas se cambie de com.bar a com.foo.bar . Al hacerlo, Qux puede depender de forma segura de Bar:2.0 porque ahora Foo ya no depende de Bar , y está utilizando una copia propia de la Bar “alterada” ubicada en otro paquete.

Me preguntaba recientemente por qué elasticsearch sombrea y reubica algunas (pero no todas) de sus dependencias. Aquí hay una explicación del mantenedor del proyecto, @kimchy :

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

Por cierto, no tengo ningún problema con proporcionar varios flasks de elasticsearch, uno con lucene no sombreado y otro con Lucene sombreado. Sin embargo, no estoy seguro de cómo hacerlo con maven. No quiero proporcionar una versión que no sombree netty / jackson, por ejemplo, debido al profundo uso intimide que elasticsearch tiene con ellos (por ejemplo, utilizando 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 el uso considerablemente menos).

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

Y otro aquí de drewr :

El sombreado es importante para mantener nuestras dependencias (especialmente netty, lucene, guava) cerca de nuestro código, de modo que podamos solucionar un problema incluso si el proveedor original está rezagado. Es posible que distribuyamos versiones modificadas 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 fines hasta que haya una solución mejor.

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 usa maven-shade-plugin en elasticsearch’s pom.xml (v0.90.5). El artifactSet::include lines le indica qué dependencias debe extraer en el archivo JAR de uber (básicamente, se descomprimen y se vuelven a empaquetar junto con las propias clases de elasticsearch cuando se produce el jar de elasticsearch de destino. (En caso de que ya no lo sepa, un archivo JAR es solo un archivo ZIP que contiene las clases, los recursos, etc. del progtwig y algunos metadatos. Puede extraer uno para ver cómo se arma.)

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, org.elasticsearch.common bajo org.elasticsearch.common .

Finalmente, la sección de filters excluye algunas cosas del JAR objective que no deberían estar allí, como los metadatos JAR, los archivos de comstackción y los archivos de texto, etc. que están empaquetados con algunas dependencias, pero que no pertenecen a un archivo JAR superior. .

   org.apache.maven.plugins maven-shade-plugin 2.1   package  shade     true   com.google.guava:guava net.sf.trove4j:trove4j org.mvel:mvel2 com.fasterxml.jackson.core:jackson-core com.fasterxml.jackson.dataformat:jackson-dataformat-smile com.fasterxml.jackson.dataformat:jackson-dataformat-yaml joda-time:joda-time io.netty:netty com.ning:compress-lzf     com.google.common org.elasticsearch.common   gnu.trove org.elasticsearch.common.trove   jsr166y org.elasticsearch.common.util.concurrent.jsr166y   jsr166e org.elasticsearch.common.util.concurrent.jsr166e   org.mvel2 org.elasticsearch.common.mvel2   com.fasterxml.jackson org.elasticsearch.common.jackson   org.joda org.elasticsearch.common.joda   org.jboss.netty org.elasticsearch.common.netty   com.ning.compress org.elasticsearch.common.compress     *:*  META-INF/license/** META-INF/* META-INF/maven/** LICENSE NOTICE /*.txt build.properties       

Pequeña advertencia

Aunque eso no describe por qué uno quisiera usar maven-shade-plugin (dado 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ó regresión en mi software.

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

Estoy publicando aquí mi solución, ya que me llevó algo de tiempo encontrar una solución decente.


Downlaod JarJar’s archivo JAR

Puede descargar el archivo 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 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 (objective) 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 anterior al carácter ‘@’): rule 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 JAR modificados en el repository 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.jar -DgroupId = io.kuku.dependencies -DadifactId = 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 -DadifactId = 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 -DadifactId = kuku-jackson-annotations -Dversion = 2.6.4 – Dpackaging = jar


Usando los JAR modificados en el pom del proyecto

En este ejemplo, este es el elemento “dependencias” en los proyectos pom:

      io.kuku.dependencies kuku-jackson-annotations 2.6.4   io.kuku.dependencies kuku-jackson-core 2.6.4   io.kuku.dependencies kuku-jackson-databind 2.6.4