Java系列---Maven插件(与maven的生命周期相关)
一、Maven插件
各个插件的执行顺序一般是:1:clean、2:resources、3:compile、4:testResources、5:testCompile、6:test、7:jar、8:install。在图中标记的地方每一行都是由冒号分隔的,前半部分是对应的插件,后半部分是插件的执行目标也就是插件执行产生的结果。现在我们来看下上面的pom文件,我们如配置了maven-compiler-plugin这个插件,其它的插件没有配置,但最后项目构建成功,说明maven内置的各种插件,如果pom中没有配置就调用默认的内置插件,如果pom中配置了就调用配置的插件。
到此我们理解maven的构建过程或者有更多的人称是打包,就是由各种插件按照一定的顺序执行来完成项目的编译,单元测试、打包、布署的完成。各种插件的执行过程也就构成的maven的生命周期(lifecycle)。生命周期(lifecycle)各个阶段并不是独立的,可以单独执行如mvn clean,也可以一起执行如mvn clean install。而且有的mvn命令其是包括多个阶段的,如mvn compile其是包括了resources和compile两个阶段。下面分别来分析各个阶段需要的插件和输出的结果
1. maven-compiler-plugin
这个插件是把class文件、配置文件打成一个jar(war或其它格式)包。依赖包是不在jar里面的,需要建立lib目录,且jar和lib目录在同级目录。常用的打包插件有maven-jar-plugin、maven-assembly-plugin、maven-shade-plugin三种,下面分别介绍下各自己pom配置和使用特点。
<plugin>
<!-- 指定maven编译的jdk版本,如果不指定,maven3默认用jdk 1.5 maven2默认用jdk1.3 -->
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<!-- 一般而言,target与source是保持一致的,但是,有时候为了让程序能在其他版本的jdk中运行(对于低版本目标jdk,源代码中不能使用低版本jdk中不支持的语法),会存在target不同于source的情况 -->
<source>1.8</source> <!-- 源代码使用的JDK版本 -->
<target>1.8</target> <!-- 需要生成的目标class文件的编译版本 -->
<encoding>UTF-8</encoding><!-- 字符集编码 -->
<skipTests>true</skipTests><!-- 跳过测试 -->
<verbose>true</verbose>
<showWarnings>true</showWarnings>
<fork>true</fork><!-- 要使compilerVersion标签生效,还需要将fork设为true,用于明确表示编译版本配置的可用 -->
<executable><!-- path-to-javac --></executable><!-- 使用指定的javac命令,例如:<executable>${JAVA_1_4_HOME}/bin/javac</executable> -->
<compilerVersion>1.3</compilerVersion><!-- 指定插件将使用的编译器的版本 -->
<meminitial>128m</meminitial><!-- 编译器使用的初始内存 -->
<maxmem>512m</maxmem><!-- 编译器使用的最大内存 -->
<compilerArgument>-verbose -bootclasspath ${java.home}\lib\rt.jar</compilerArgument><!-- 这个选项用来传递编译器自身不包含但是却支持的参数选项 -->
</configuration>
</plugin>
2. maven-jar-plugin
<plugins>
<plugin>
<artifactId>maven-jar-plugin</artifactId>
<executions>
<!-- monitor 包-jar -->
<execution>
<id>monitor</id>
<goals>
<goal>jar</goal>
</goals>
<phase>package</phase>
<configuration>
<classifier>monitor</classifier>
<includes>
<include>**/xx/xx/xx/xx/**</include>
<include>**/xx/xx/xx/xx/**</include>
</includes>
</configuration>
</execution>
</executions>
</plugin>
编译时,配置非maven 指定的jar包路径
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.3.2</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<encoding>UTF-8</encoding>
<compilerArgs>
<arg>-extdirs</arg>
<arg>${project.basedir}/src/main/resources/lib/</arg>
</compilerArgs>
</configuration>
</plugin>
3. maven-dependency-plugin
<!-- 拷贝依赖包 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>2.5.1</version>
<executions>
<execution>
<id>copy</id>
<phase>install</phase>
<goals>
<goal>copy-dependencies</goal>
</goals>
<configuration>
<outputDirectory>${project.build.directory}/lib</outputDirectory>
</configuration>
</execution>
</executions>
</plugin>
4. maven-shade-plugin
所有的依赖包打入到可执行jar包,如果同级目录有其它可执行jar,依赖可能会产生冲突,且运行jar时,有时会出现SF、DSA、RSA文件冲突的提示,需要排除META-INF目录下的文件
将部分jar包添加或排除
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.1.1</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<artifactSet>
<excludes>
<exclude>jmock:*</exclude>
<exclude>*:xml-apis</exclude>
<exclude>org.apache.maven:lib:tests</exclude>
<exclude>log4j:log4j:jar:</exclude>
</excludes>
<includes>
<include>junit:junit</include>
</includes>
</artifactSet>
</configuration>
</execution>
</executions>
</plugin>
将依赖jar包内部资源添加或排除
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.1.1</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<filters>
<filter>
<artifact>junit:junit</artifact>
<includes>
<include>junit/framework/**</include>
<include>org/junit/**</include>
</includes>
<excludes>
<exclude>org/junit/experimental/**</exclude>
<exclude>org/junit/runners/**</exclude>
</excludes>
</filter>
<filter>
<artifact>*:*</artifact>
<excludes>
<exclude>META-INF/*.SF</exclude>
<exclude>META-INF/*.DSA</exclude>
<exclude>META-INF/*.RSA</exclude>
</excludes>
</filter>
</filters>
</configuration>
</execution>
</executions>
</plugin>
自动将所有不使用的类排除
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.1.1</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<minimizeJar>true</minimizeJar>
</configuration>
</execution>
</executions>
</plugin>
将依赖的类重命名并打包进来 (隔离方案)
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.1.1</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<relocations>
<relocation>
<pattern>org.codehaus.plexus.util</pattern>
<shadedPattern>org.shaded.plexus.util</shadedPattern>
<excludes>
<exclude>org.codehaus.plexus.util.xml.Xpp3Dom</exclude>
<exclude>org.codehaus.plexus.util.xml.pull.*</exclude>
</excludes>
</relocation>
</relocations>
</configuration>
</execution>
</executions>
</plugin>
修改包的后缀名
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.1.1</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<shadedArtifactAttached>true</shadedArtifactAttached>
<shadedClassifierName>jackofall</shadedClassifierName> <!-- Any name that makes sense -->
</configuration>
</execution>
</executions>
</plugin>
问题:Invalid signature file digest for Manifest main attributes
原因:有些jar包生成时,会 使用jarsigner生成文件签名(完成性校验),分为两个文件存放在META-INF目录下:
a signature file, with a .SF extension;
a signature block file, with a .DSA, .RSA, or .EC extension;
解决方案:生成 uber-jar时,将这些排除掉,不再进行完成性校验,如下所示:
<configuration>
<filters>
<filter>
<artifact>*:*</artifact>
<excludes>
<exclude>META-INF/*.SF</exclude>
<exclude>META-INF/*.DSA</exclude>
<exclude>META-INF/*.RSA</exclude>
</excludes>
</filter>
</filters>
</configuration>
较详细的版本
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>2.4.3</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<filters>
<filter>
<artifact>*:*</artifact>
<excludes>
<exclude>META-INF/*.SF</exclude>
<exclude>META-INF/*.DSA</exclude>
<exclude>META-INF/*.RSA</exclude>
</excludes>
</filter>
</filters>
<transformers>
<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>
<transformer
implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
<resource>META-INF/spring.tooling</resource>
</transformer>
<transformer
implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<mainClass>com.xxx.xxxInvoke</mainClass>
</transformer>
</transformers>
<minimizeJar>true</minimizeJar>
<shadedArtifactAttached>true</shadedArtifactAttached>
</configuration>
</execution>
</executions>
</plugin>
5. maven-resources-plugin
resource插件的功能就是把项目需要的配置文件拷贝到指定的目当,默认是拷贝src\main\resources目录下的件到classes目录下,当然可以自己来配置源目录和输出目录。resources插件一般不单独执行,complie插件执行时会先调用resources插件
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<version>2.6</version>
<executions>
<execution>
<id>copy-resources</id>
<!-- 在default生命周期的 validate阶段就执行resources插件的copy-resources目标 -->
<phase>validate</phase>
<goals>
<goal>copy-resources</goal>
</goals>
<configuration>
<!-- 指定resources插件处理资源文件到哪个目录下 -->
<outputDirectory>${project.build.outputDirectory}</outputDirectory>
<!-- 也可以用下面这样的方式(指定相对url的方式指定outputDirectory) <outputDirectory>target/classes</outputDirectory> -->
<!-- 待处理的资源定义 -->
<resources>
<resource>
<!-- 指定resources插件处理哪个目录下的资源文件 -->
<directory>src/main/${deploy.env}/applicationContext.xml</directory>
<!-- 指定不需要处理的资源 <excludes> <exclude>WEB-INF/*.*</exclude> </excludes> -->
<!-- 是否对待处理的资源开启过滤模式 (resources插件的copy-resources目标也有资源过滤的功能,这里配置的
这个功能的效果跟<build><resources><resource>下配置的资源过滤是一样的,只不过可能执行的阶段不一样, 这里执行的阶段是插件指定的validate阶段,<build><resources><resource>下的配置将是在resources插件的resources目标执行时起作用(在process-resources阶段)) -->
<filtering>false</filtering>
</resource>
</resources>
</configuration>
<inherited></inherited>
</execution>
</executions>
</plugin>
6. maven-assembly-plugin
这个插件可以把所有的依赖包打入到可执行jar包。但是该插件有个bug会缺失spring的xds文件,导致无法运行jar,同时如果同级目录还有其它可执行jar文件依赖可能会产生冲突。
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
<archive>
<manifest>
<mainClass>com.xxx.xxxService</mainClass>
</manifest>
</archive>
</configuration>
<executions>
<execution>
<id>make-assembly</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
7. maven-antrun-plugin
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-antrun-plugin</artifactId>
<version>1.8</version>
<executions>
<execution>
<phase>install</phase>
<goals>
<goal>run</goal>
</goals>
<configuration>
<tasks>
<echo>Building 描述信息 START....</echo>
<!-- 删除目录 -->
<delete dir="target/dir"/>
<!-- 删除目录 -->
<mkdir dir="target/dir"/>
<!-- 复制目录文件 复制到-todir 要复制的目录-fileset -->
<copy todir="target/dir/xxx">
<fileset dir="target/classes/config"/>
</copy>
<!-- 删除文件 -->
<delete>
<fileset dir="target/xxx/lib/xxx" includes="xxx*.jar"/>
<fileset dir="target/xxx/lib/xxx" includes="xxx-*.jar"/>
</delete>
<!-- 将指定目录压缩ZIP -->
<copy todir="target/tempbuild/xxx">
<fileset dir="target/xxx"/>
</copy>
<tstamp>
<format property="current.date.time" pattern="yyyyMMddHHmmss"/>
</tstamp>
<zip destfile="target/xxx_${version}_${current.date.time}.zip">
<zipfileset dir="target/tempbuild"/>
</zip>
<checksum file="target/xxx_${version}_${current.date.time}.zip"
forceOverwrite="yes" algorithm="MD5" fileext=".MD5"></checksum>
<delete dir="target/tempbuild"/>
<echo>Building 描述信息 END</echo>
</tasks>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
二、maven三种打包插件
第一种:可执行jar与依赖分开,依赖在lib目录里,需要jar和lib目录在同级目录,
优点:jar文件很小
缺点:需要放置lib文件夹在平级目录
1 <plugin>
2 <groupId>org.apache.maven.plugins</groupId>
3 <artifactId>maven-jar-plugin</artifactId>
4 <version>2.6</version>
5 <configuration>
6 <archive>
7 <manifest>
8 <addClasspath>true</addClasspath>
9 <classpathPrefix>lib/</classpathPrefix>
10 <mainClass>com.xxx.xxxService</mainClass>
11 </manifest>
12 </archive>
13 </configuration>
14 </plugin>
15 <plugin>
16 <groupId>org.apache.maven.plugins</groupId>
17 <artifactId>maven-dependency-plugin</artifactId>
18 <version>2.10</version>
19 <executions>
20 <execution>
21 <id>copy-dependencies</id>
22 <phase>package</phase>
23 <goals>
24 <goal>copy-dependencies</goal>
25 </goals>
26 <configuration>
27 <outputDirectory>${project.build.directory}/lib</outputDirectory>
28 </configuration>
29 </execution>
30 </executions>
31 </plugin>
第二种:把所有依赖打进同一个jar包里。
缺点:jar文件会比较大,同时该插件有个bug会缺失spring的xds文件,导致无法运行jar,同时如果同级目录还有其它可执行jar文件依赖可能会产生冲突
优点:方便快捷,打包完直接就能运行。
1 <plugin>
2 <artifactId>maven-assembly-plugin</artifactId>
3 <configuration>
4 <descriptorRefs>
5 <descriptorRef>jar-with-dependencies</descriptorRef>
6 </descriptorRefs>
7 <archive>
8 <manifest>
9 <mainClass>com.xxx.xxxService</mainClass>
10 </manifest>
11 </archive>
12 </configuration>
13 <executions>
14 <execution>
15 <id>make-assembly</id>
16 <phase>package</phase>
17 <goals>
18 <goal>single</goal>
19 </goals>
20 </execution>
21 </executions>
22 </plugin>
第三种:所有依赖打到同一个jar文件里。
缺点:jar文件过大、如果同级目录有其它可执行jar,依赖可能会产生冲突
优点:不会有任何bug,直接打成可执行jar文件,最省事。
1 <plugin>
2 <groupId>org.apache.maven.plugins</groupId>
3 <artifactId>maven-shade-plugin</artifactId>
4 <version>2.4.3</version>
5 <executions>
6 <execution>
7 <phase>package</phase>
8 <goals>
9 <goal>shade</goal>
10 </goals>
11 <configuration>
12 <filters>
13 <filter>
14 <artifact>*:*</artifact>
15 <excludes>
16 <exclude>META-INF/*.SF</exclude>
17 <exclude>META-INF/*.DSA</exclude>
18 <exclude>META-INF/*.RSA</exclude>
19 </excludes>
20 </filter>
21 </filters>
22 <transformers>
23 <transformer
24 implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
25 <resource>META-INF/spring.handlers</resource>
26 </transformer>
27 <transformer
28 implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
29 <resource>META-INF/spring.schemas</resource>
30 </transformer>
31 <transformer
32 implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
33 <resource>META-INF/spring.tooling</resource>
34 </transformer>
35 <transformer
36 implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
37 <mainClass>com.xxx.xxxInvoke</mainClass>
38 </transformer>
39 </transformers>
40 <minimizeJar>true</minimizeJar>
41 <shadedArtifactAttached>true</shadedArtifactAttached>
42 </configuration>
43 </execution>
44 </executions>
45 </plugin>
三、找不到主属清单原因
- 打包时jdk和jre区别设置,优选jdk
在项目上右键-->build path---->config build path 选择本机jdk不要jre
右键ruan as ---> run configuartions指定jdk版本
- project栏 ---> clean 最粗暴的方式
- Maven clean
- Maven-jar-pluge打包插件指定 mainclass