Hacer un zip para distribuir
Qué es maven-assembly-plugin[editar]
maven-assembly-plugin es un plugin de maven que permite generar varios tipos de empaquetados de nuestro proyecto. Un jar ejecutable con todas las dependencias dentro, un zip con nuestros jar, ficheros de configuración, iconos y lo que necesitemos para poder distribuirlo, un zip de fuentes, etc. De esta forma, llevándonos el zip y desempaquetándolo tendremos nuestro programa listo par ejecutar, para compilar o lo que necesitemos.
Empaquetados predefinidos en maven-assembly-plugin[editar]
El plugin assembly de Maven tiene varios tipos de empaquetados predefinidos. Son los siguientes
- bin. Genera ficheros comprimidos tar.gz, tar.bz2, y zip que dentro llevan el mismo jar que
mvn package
más los ficheros README, LICENSE y NOTICE si los tienes en el raíz de tu proyecto Maven. - jar-with-dependencies. Genera un jar con todoas las dependencias de nuestro proyecto dentro. Si configurammos cual es la clase
main
en el fichero de manifiesto, este jar por sí solo se puede ejecutar conjava -jar mijar-jar-with-dependencies.jar
- src. Genera ficheros comprimidos tar.gz, tar.bz2 y zip con todo el contenido de nuestro directorio
src
de nuestro proyecto Maven. - project. Genera ficheros comprimidos tar.gz, tar.bz2 y zip con todo el contenido de nuestro proyecto Maven excepto el directorio
target
Vamos a ver con detalle es segundo, jar-with-dependencies
, porque es uno de los más útiles.
maven-assembly-plugin jar-with-dependencies[editar]
Para usar cualquiera de los empequetados predefinidos, debemos añadir el plugin en nuestro <pom.xml>. Indicamos en él el descriptor del tipo de empaquetado que queremos que se ejecute. Este descriptor es una de las opciones que hemos visto antes: bin
, jar-with-dependencies
, src
o project
. Para el caso de jar-with-dependencies quedaría así
<project>
...
<build>
<plugins>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<version>3.6.0</version>
<configuration>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
</plugin>
...
</plugins>
...
</build>
...
</project>
La configuración sería igual para cualquiera de los descriptores predefinidos, solo cambia el contenido del tag XML <descriptorRef>
.
Para obtener el jar que genera jar-with-dependencies ejecutaríamos el comando maven
mvn package assembly:single
Es importante asegurarnos que el jar normal de nuestro proyecto está construido antes de llamar a assembly:single
. Si no, no se genera y no se incluye en nuestro jar-with-dependencies
El jar se genera en el directorio target
y tiene el nombre <mi proyecto>-<version>-jar-with-dependencies.jar
. Pero todavía no es ejecutable. Nos falta añadir cuál es la clase main
en el fichero de manifiesto. Esto se hace en la misma configuración del plugin de ls siguiente manera
<project>
...
<build>
<plugins>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<version>3.6.0</version>
<configuration>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
<archive>
<manifest>
<mainClass>com.chuidiang.examples.App</mainClass>
</manifest>
</archive>
</configuration>
</plugin>
...
</plugins>
...
</build>
...
</project>
He puesto mi clase com.chuidiang.examples.App
que es la que tiene el método main
. Si ahora generamos el jar nuevamente
mvn clean package assembly:single
El jar generado se puede ejecutar sin más con
java -jar miproyecto-1.0-SNAPSOT-jar-with-dependencies.jar
maven-assembly-plugin finalName y appendAssemblyId[editar]
Por defecto cuando generamos un empaquetado con maven-assembly-plugin, al fichero se le añade la coletilla del descriptorRef
. En los ejemplos que hemos visto, esta coletilla es muy larga: jar-with-dependencies. Afortunamente, podemos cambiar el nombre que queramos que tenga nuestro jar con finalName y si queremos que se le añada o no la coletilla del descriptorRef
con appendAssemblyId. En la configuración del fichero XML, pondriamos estas dos propiedades así
...
<artifactId>maven-assembly-plugin</artifactId>
<version>3.6.0</version>
<configuration>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
<archive>
<manifest>
<mainClass>com.chuidiang.examples.App</mainClass>
</manifest>
</archive>
<finalName>nombre-del-jar</finalName>
<appendAssemblyId>false</appendAssemblyId>
</configuration>
...
Esto generará un fichero nombre-del-jar.jar
Configurar nuestro propio zip[editar]
Si no nos gustan los predefinidos, podemos configurar maven-assembly-plugin para que genere los zip con lo que necesitemos. Para este ejemplo, vamos a generar un zip tenga la típica estructura con directorios bin, conf y lib. En bin meteremos nuestro jar ejecutable, en lib todos los jar de los que dependemos y en conf los ficheros de configuración de nuestro proyecto.
Vamos a seguir los siguientes pasos
- En el directorio src/main/config de nuestro proyecto maven ponemos los ficheros de configuración que necesitemos. El directorio puede llamarse como quieras, pongo src/main/config por seguir la estructura de directorios de Maven.
- Usando maven-jar-plugin creamos el fichero de manifiesto de nuestro jar para que sea ejecutable. Es decir, le ponemos el Main-class y el classpath
- Creamos un fichero src/main/assembly/dep.xml donde indicaremos a maven-assembly-plugin como construir el zip. Nuevamente, tanto el directorio como el nombre del fichero puede ser el que quieras.
- Configuramos nuestro pom.xml para que el comando mvn package assembly:single genere el zip según hemos definido.
Vamos con el detalle de los pasos uno a uno.
Ficheros de configuración en src/main/config[editar]
Nada especial. Crear la estructura de directorios y metemos un fichero cualquiera configuration.properties que nos sirva para el ejemplo.
Hacer que el jar sea ejecutable[editar]
En el ejemplo de jar-with-dependencies lo habiamos hecho poniendo <archive> en la configuración de maven-assembly-plugin. Esto no nos vale en este caso. maven-assembly-plugin hace caso a lo que ponga su configuración <archive> si va a generar un jar. No hace caso si, como en nuestro ejemplo, va a generar un zip.
Así que lo configuramos con maven-jar-plugin. En nuestro pom.xml ponemos un plugin más
<project>
...
<build>
<plugins>
<plugin>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<archive>
<manifest>
<mainClass>com.chuidiang.examples.App</mainClass>
<addClasspath>true</addClasspath>
<classpathPrefix>../lib/</classpathPrefix>
</manifest>
</archive>
</configuration>
</plugin>
...
Hemos puesto
- Nuestra clase main en <mainClass>
- Indicamos que queremos que añada la entrada classpath al fichero de manifiesto con <addClasspath>
- He indicamos el path relativo donde van a estar las dependencias respecto a nuestro jar. Nuestro jar estará en el directorio bin, las dependencias en lib, así que el path relativo es ../lib/. Ponemos esto en classpathPrefix
Fichero de configuración de maven-assembly-plugin[editar]
El contenido del fichero src/main/assembly/dep.xml puede ser el siguiente
<assembly>
<id>my-ref-id</id>
<formats>
<!-- Formatos en el que queremos el zip -->
<format>tar.gz</format>
<format>tar.bz2</format>
<format>zip</format>
</formats>
<!-- Ahora que cosas queremos -->
<fileSets>
<!-- Nuestros ficheros de configuracion guardados en src/main/config-->
<fileSet>
<directory>src/main/config</directory>
<!-- Queremos que esten en un subdirectorio CONFIG dentro del zip -->
<outputDirectory>/config</outputDirectory>
</fileSet>
</fileSets>
<files>
<file>
<!-- El jar generado por nuestro proyecto -->
<source>target/${project.build.finalName}.jar</source>
<!-- lo queremos en el subdirectorio bin -->
<outputDirectory>/bin</outputDirectory>
</file>
</files>
<!-- Queremos incluir los jar de los que dependemos -->
<dependencySets>
<dependencySet>
<!-- Queremos los jar dentro de un directorio lib dentro del zip -->
<outputDirectory>/lib</outputDirectory>
<!-- No queremos que meta aqui tambien el jar de nuestro proyecto -->
<useProjectArtifact>false</useProjectArtifact>
</dependencySet>
</dependencySets>
</assembly>
Hay cinco puntos importantes ahí.
- Ponemos un id a nuestro gusto. En el ejemplo my-ref-id
- Indicamos que tipo de empaquetamiento queremos. En el ejemplo, zip, tar.gz y tar.bz2. Podemos quitar los que no nos interesen.
- Todo el contenido del zip:
- En el bloque <fileSets> (directorios), metemos el de los ficheros de configuración. Indicamos dónde están en nuestro proyecto Maven con <directory> y dónde lo queremos dentro del zip en <outputDirectory>
- En el bloque <files> (fihero), metemos ficheros sueltos que nos intesen. En nuestro ejemplo, el jar generado por nuestro proyecto. Indicamos dónde está con <source> y dónde lo queremos con <outputDirectory>
- En el bloque <dependencySets> tenemos las dependencias. No necesitamos decir dónde están, Maven lo sabe. Indicamos dónde están con <outputDirectory>. Un detalle a tener en cuenta es que el jar de nuestro proyecto forma parte de las dependencias. Como ya lo hemos metido en el directorio bin, no queremos que se meta aquí también. Por ello <useProjectArtifact> lo ponemos a false
Configuración de maven-assembly-plugin en pom.xml[editar]
Luego, en el pom.xml simplemente indicarle a maven-assembly-plugin dónde está el fichero dep.xml en vez de darle un descriptorRef
<project>
...
<build>
...
<plugins>
...
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<descriptors>
<!-- Sitio en el que esta el fichero anterior -->
<descriptor>src/main/assembly/dep.xml</descriptor>
</descriptors>
</configuration>
</plugin>
</plugins>
</build>
</project>
Generar el zip con maven-assembly-plugin[editar]
Una vez configurado todo, el comando
mvn package assembly:single
generará en el directorio target del proyecto los tres zip indicados antes (zip, tar.gz y tar.bz2)