Maven三种打包方式
Maven的打包插件
- maven-jar-plugin,默认的打包插件,用来打普通的project JAR包
- maven-shade-plugin,用来打可执行JAR包,也就是所谓的fat JAR包
- maven-assembly-plugin,支持自定义的打包结构,也可以定制依赖项等
maven-jar-plugin官方地址:https://maven.apache.org/plugins/maven-jar-plugin/
maven-dependency-plugin官方地址:https://maven.apache.org/plugins/maven-dependency-plugin/index.html
使用maven-jar-plugin和maven-dependency-plugin插件打包
<build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-jar-plugin</artifactId> <version>2.6</version> <configuration> <archive> <manifest> <addClasspath>true</addClasspath> <classpathPrefix>lib/</classpathPrefix> <mainClass>com.xxg.Main</mainClass> </manifest> </archive> </configuration> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-dependency-plugin</artifactId> <version>2.10</version> <executions> <execution> <id>copy-dependencies</id> <phase>package</phase> <goals> <goal>copy-dependencies</goal> </goals> <configuration> <outputDirectory>${project.build.directory}/lib</outputDirectory> </configuration> </execution> </executions> </plugin> </plugins> </build>
maven-jar-plugin用于生成META-INF/MANIFEST.MF文件的部分内容
- <mainClass>com.xxg.Main</mainClass>指定MANIFEST.MF中的Main-Class
- <addClasspath>true</addClasspath>会在MANIFEST.MF加上Class-Path项并配置依赖包
- <classpathPrefix>lib/</classpathPrefix>指定依赖包所在目录
MANIFEST.MF文件片段
Class-Path: lib/commons-logging-1.2.jar lib/commons-io-2.4.jar Main-Class: com.xxg.Main
只是生成MANIFEST.MF文件还不够,maven-dependency-plugin插件用于将依赖包拷贝到<outputDirectory>${project.build.directory}/lib</outputDirectory>指定的位置,即lib目录下
指定了Main-Class,有了依赖包,那么就可以直接通过java -jar xxx.jar运行jar包
这种方式生成jar包有个缺点,就是生成的jar包太多不便于管理,下面两种方式只生成一个jar文件,包含项目本身的代码、资源以及所有的依赖包
maven-assembly-plugin 自定义打包插件
官方地址:https://maven.apache.org/plugins/maven-assembly-plugin/
<build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-assembly-plugin</artifactId> <version>${maven-assembly-plugin.version}<version> <executions> <execution> <id>make-assembly</id> <!-- 绑定到package生命周期 --> <phase>package</phase> <goals> <!-- 只运行一次 --> <goal>single</goal> </goals> </execution> </executions> <configuration> <descriptors> <!-- 配置描述符文件 --> <descriptor>src/main/assembly/assembly.xml</descriptor> </descriptors> <skipAssembly>${assemmbly.skip}</skipAssembly> <!-- 打包后不带该后缀 --> <appendAssemblyId>false</appendAssemblyId> <!-- 也可以使用Maven预配置的描述符 <descriptorRefs> <descriptorRef>jar-with-dependencies</descriptorRef> </descriptorRefs> --> <!--归档--> <archive> <!--清单--> <manifest> <mainClass>cn.techny.start.Appliation</mainClass> </manifest> </archive> <!--打包时的名称,如果没有设置,打包后的包名是artifactId与version拼接的结果-->
<finalName>pdms</finalName> </configuration> </plugin> </plugins> </build>
若项目中用到spring Framework,用这种方式打出来的包运行时会出错
要真正达到自定义打包的效果,就需要自己写描述符文件,格式为XML
assembly官方地址:http://maven.apache.org/plugins/maven-assembly-plugin/assembly.html
<assembly > <id>assembly</id> <!--支持 zip,tar,tar.gz,tar.bz2,jar,dir,war 等 --> <formats> <format>tar.gz</format> </formats> <!--在tar.gz压缩包下是否生成和项目名相同的根目录--> <includeBaseDirectory>true</includeBaseDirectory> <fileSets> <!--fileSet把某些目录指定要打包的文件并指定输出文件夹--> <fileSet> <directory>src/main/bin</directory> <includes> <include>*.sh</include> </includes> <outputDirectory>bin</outputDirectory> <!--fileMode是linux的rwx对应421--> <fileMode>0755</fileMode> </fileSet> <fileSet> <directory>src/main/conf</directory> <outputDirectory>conf</outputDirectory> </fileSet> <fileSet> <directory>src/main/sql</directory> <includes> <include>*.sql</include> </includes> <outputDirectory>sql</outputDirectory> </fileSet> <fileSet> <directory>target/classes/</directory> <includes> <include>*.properties</include> <include>*.xml</include> <include>*.txt</include> </includes> <outputDirectory>conf</outputDirectory> </fileSet> </fileSets> <files> <file> <source>target/${project.artifactId}-${project.version}.jar</source> <outputDirectory>.</outputDirectory> </file> </files> <dependencySets> <dependencySet> <!--是否把本项目添加到依赖文件夹下--> <useProjectArtifact>true</useProjectArtifact> <unpack>false</unpack> <!--打包时的scope,如果不配置默认就是runtime--> <scope>runtime</scope> <outputDirectory>lib</outputDirectory> <!--映射出来的文件--> <outputFilenameMapping></outputFilenameMapping> </dependencySet> </dependencySets> </assembly>
id与format
- formats是assembly插件支持的打包文件格式,有zip、tar、tar.gz、tar.bz2、jar、war
- 可以同时定义多个format
- id则是添加到打包文件名的标识符,用来做后缀
- 也就是说,如果按上面的配置,生成的文件就是a r t i f a c t I d − {artifactId}-artifactId−{version}-assembly.tar.gz
fileSets/fileSet
用来设置一组文件在打包时的属性。
directory
源目录的路径
includes/excludes
设定包含或排除哪些文件,支持通配符
fileMode
指定该目录下的文件属性,采用Unix八进制描述法,默认值是0644
outputDirectory
生成目录的路径
files/file
与fileSets大致相同,不过是指定单个文件,并且还可以通过destName属性来设置与源文件不同的名称
dependencySets/dependencySet
用来设置工程依赖文件在打包时的属性。也与fileSets大致相同,不过还有两个特殊的配置:
- unpack:布尔值,false表示将依赖以原来的JAR形式打包,true则表示将依赖解成*.class文件的目录结构打包。
- scope:表示符合哪个作用范围的依赖会被打包进去。compile与provided都不用管,一般是写runtime。
用maven-shade-plugin插件打包
maven-shade-plugin官方地址:https://maven.apache.org/plugins/maven-shade-plugin/index.html
<build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-shade-plugin</artifactId> <version>2.4.1</version> <executions> <execution> <phase>package</phase> <goals> <goal>shade</goal> </goals> <configuration> <transformers> <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer"> <mainClass>com.xxg.Main</mainClass> </transformer> <transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer"> <resource>META-INF/spring.handlers</resource> </transformer> <transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer"> <resource>META-INF/spring.schemas</resource> </transformer> </transformers> </configuration> </execution> </executions> </plugin> </plugins> </build>
配置完成后,执行mvn package即可打包
如果项目中用到了Spring Framework,将依赖打到一个jar包中,运行时会出现读取XML schema文件出错
原因是Spring Framework的多个jar包中包含相同的文件spring.handlers和spring.schemas,如果生成一个jar包会互相覆盖
为了避免互相影响,使用AppendingTransformer来对文件内容追加合并
睁开眼,书在面前 闭上眼,书在心里