默认的情况下,当直接执行maven项目的编译命令时,对于结果来说是不打第三方包的,只有一个单独的代码jar,想要打一个包含其他资源的完整包就需要用到maven编译插件,使用时分以下几种情况
第一种:当只是想单纯的开发一个maven项目,不涉及其他复杂的项目结构,最后只需要一个全部资源可执行jar,就用如下插件pom
<build><plugins><!-- Maven Assembly Plugin 是maven官方的编译打包插件--><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-assembly-plugin</artifactId><version>3.3.0</version><!-- 插件的配置参数相关--><configuration><!-- 当你在打可执行包,也就是结果包是一个jar时,可以指定主类--><archive><manifest><mainClass>com.yourpackage.MainClass</mainClass> <!-- 指定主类 --></manifest></archive><!-- 这里需要给一个结果包的后缀,用来区分--><descriptorRefs><descriptorRef>jar-with-dependencies</descriptorRef></descriptorRefs></configuration><!-- 插件的执行阶段定义,可以有多个,不过一般一个打包的就够了 --><executions><execution><!-- 这个id是自定的,保证有多个执行阶段的时候是唯一的就行 --><id>make-assembly</id><!-- 这个执行阶段在maven的那个阶段生效,这里绑定在打包时生效 --><phase>package</phase><!-- 这个single是固定的不用变,意思是根据给定的或者默认的配置来执行编译,默认时是打当前项目的所有dependencies为一个完整包,这个参数不要过多纠结官方文档中也只有这个,你要能力够可以自己封装 --><goals><goal>single</goal></goals></execution></executions></plugin></plugins>
</build>
打包后项目的输出路径下,除了原本的最小jar外,会有一个包名包含jar-with-dependencies的jar
第二种:assembly是一个比较好用的编译插件,无论是单独打jar,还是整个项目打归档类的包,都能胜任,不过早些年ssm那个时代,Java常用的编译插件是compiler,这个插件现在也有人用,不过它在打包的时候常常出问题,所以用它来打包的话,保险起见要指定resources。同时它只能打jar包,并且不能指定主类,在ssm这种web开发使用到的比较多,而 Spring boot之后官方提供了自己的编译插件,再加上它没有assembly那么好用,所以现在用的不多
<build><plugins><!-- maven在进行一些编译操作所使用的插件 --><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><version>3.5.1</version><configuration><source>1.8</source><target>1.8</target><encoding>UTF-8</encoding></configuration></plugin></plugins><resources><resource><directory>src/main/java</directory><!--所在的目录--><includes><include>**/*.properties</include><include>**/*.xml</include></includes><filtering>false</filtering></resource><resource><directory>src/main/resources</directory><!--所在的目录--><includes><include>**/*.xml</include><include>**/*.properties</include></includes><filtering>false</filtering></resource></resources></build>
第三种:在多数情况下项目结构比较复杂,比如父子项目,或者需要打一些其他特别的资源文件到结果包中,又或者结果不止需要插件打默认的jar包,因此除非是某个模块或者项目真的就只打一个简单的完整包会使用第一种编译方式外,其他情况需要提供assembly完整的打包说明文件,使用方式如下
首先在需要的项目pom中声明打包用的插件。这里注意一下,一定要把所有需要打包的资源放在一个专门用来打包的子模块中,因为这个插件没办法跨项目打资源,总之我这边本地是尝试了之后没发现能跨模块打资源的方法,最多能做到按照描述文件各打各的,但是然并朊啊
<build><plugins><plugin><!-- 插件和版本 --><groupId>org.apache.maven.plugins</groupId><artifactId>maven-assembly-plugin</artifactId><version>3.3.0</version><!-- 这里!!!!需要给插件提供一个打包阶段的描述文件,并且当你这样使用的时候,第一种情况的主类和前缀配置就不要配了,一来是大概率不生效,二来这种给定描述文件的方式通常是用来打归档类结果文件的,也就是tar这种,而不是一个单一的可执行jar --><configuration><descriptors><!-- ${project.basedir}是maven自带的变量,可以获取当前项目的根路径 --><descriptor>${project.basedir}/assembly.xml</descriptor></descriptors></configuration><executions><execution><id>make-assembly</id><phase>package</phase><goals><goal>single</goal></goals></execution></executions></plugin></plugins></build>
下面是描述文件的内容
<assembly><!-- 设置结果集的id,最后会作为结果文件名的后缀 --><id>bin</id><!-- 指定结果集的格式,可以支持zip, tar, tar.gz等,可以写多个结果就会有对应的多个 --><formats><format>tar.gz</format></formats><includeBaseDirectory>true</includeBaseDirectory><!-- 指定结果集中包含的文件集 --><fileSets><fileSet><directory>${project.basedir}/bin</directory><outputDirectory>/bin</outputDirectory><includes><include>*</include></includes><fileMode>0644</fileMode></fileSet></fileSets><!-- 指定程序集中包含的依赖项集,这个一般使用的时候就是固定的格式 --><dependencySets><dependencySet><!-- 包含所有依赖项,到lib --><outputDirectory>/lib</outputDirectory><!-- 包含项目自身的jar --><useProjectArtifact>true</useProjectArtifact><!-- 还可以指定依赖即便但是一般不写,打全部的 <scope>runtime</scope>--></dependencySet></dependencySets></assembly>
上面这个文件内容是通常情况下的使用内容,一般也够了,但是描述文件中还有其他的标签可以用,你可以在网上查它的约束消息,下面一些可能会用到的标签,大家参考一下就行了
<assembly><!-- 设置结果集的id,最后会作为后缀 --><id>bin</id><!-- 指定结果集的格式,可以支持zip, tar, tar.gz等 --><formats><format>tar.gz</format><format>dir</format></formats><!-- 在结果集中是否包含一个基本目录,默认值是true,就好比我们使用开源软件解压之后是个完整的目录,而不是全部在当前目录解压所有文件 --><includeBaseDirectory>true</includeBaseDirectory><!-- 设置生成程序集存档的基本目录名,如果没有设置并且includeBaseDirectory为true,则使用${project.build.finalName}作为基本目录名,一般都用默认的 --><baseDirectory>${project.build.finalName}</baseDirectory><!-- 在最终档案中是否包含一个站点目录,默认值是false,这个只有在特殊情况在可能用true --><includeSiteDirectory>false</includeSiteDirectory><!-- 这个很少会用到,它是用来让插件自动合并或定制一些文件,比如多个properties文件聚合成一个,有需要的话网上找找案例就行 --><containerDescriptorHandlers><containerDescriptorHandler><handlerName>metaInf-services</handlerName><configuration><!-- 配置选项,具体根据需求填写 --></configuration></containerDescriptorHandler></containerDescriptorHandlers><!-- 指定包含在程序集中的模块文件,这个也用的很少,因为程序运行的jar一般会打到一个固定的路径下,而且如果你的使用方式和我一样,那么需要的资源就已经在一个专门编译用的子模块下了,不会涉及到从其他模块里面再去指定 --><moduleSets><moduleSet><!-- 包含当前项目的所有模块 --><useAllReactorProjects>true</useAllReactorProjects><!-- 指定包含或排除的模块 --><includes><include>com.example:my-module</include></includes><excludes><exclude>com.example:excluded-module</exclude></excludes><!-- 设置输出目录 --><outputDirectory>modules</outputDirectory></moduleSet></moduleSets><!-- 指定程序集中包含的文件集,这个很长用 --><fileSets><fileSet><directory>src/main/resources</directory><outputDirectory>conf</outputDirectory><includes><include>*.xml</include><include>*.properties</include></includes><fileMode>0644</fileMode></fileSet></fileSets><!-- 指定程序集中包含的依赖项集 --><dependencySets><dependencySet><!-- 包含所有依赖项 --><outputDirectory>lib</outputDirectory><scope>runtime</scope></dependencySet></dependencySets>
</assembly>
第四种情况:Maven项目可以用来Java和Scala混编,但是上面的maven-assembly-plugin编译不了scala文件,所以需要用下面的两个插件配合,一个是java的,一个是scala的,先编译最后统一用shade打包,但是这种方式只能打可执行jar,至于混编下打tar包, 目前还没有遇到这种情况。
<build><!-- 这里规定插件版本 --><pluginManagement><plugins><!-- 编译scala的插件 --><plugin><groupId>net.alchim31.maven</groupId><artifactId>scala-maven-plugin</artifactId><version>3.2.2</version></plugin><!-- 编译java的插件 --><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><version>3.5.1</version></plugin></plugins></pluginManagement><plugins><!-- 规定Scala怎么编译 注意这里只规定编译,不规定打包--><plugin><groupId>net.alchim31.maven</groupId><artifactId>scala-maven-plugin</artifactId><executions><!-- 这两个 Execution,规定编译源码添加资源 ,第2个测试编译可以不要--><execution><id>scala-compile-first</id><phase>process-resources</phase><goals><goal>add-source</goal><goal>compile</goal></goals></execution><execution><id>scala-test-compile</id><phase>process-test-resources</phase><goals><goal>testCompile</goal></goals></execution></executions></plugin><!-- 这里是规定怎么编译java --><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><configuration><source>1.8</source><target>1.8</target><encoding>UTF-8</encoding></configuration><executions><!-- 作用和上面的一样,只不过这里不用显示的调用add来添加资源 --><execution><phase>compile</phase><goals><goal>compile</goal></goals></execution></executions></plugin><!-- shade插件用来把上面的所有资源统一打包成一个新的jar --><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><transformers><transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer"><mainClass>com.example.MainClass</mainClass> <!-- 如果需要打包可执行jar,可以在这里指定主类,不过一般用不着,和混编一般是应用在数据引擎或实时处理上的,对应的引擎有主类的指定,直接上传一个jar包就好 --></transformer></transformers><filters><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></plugins></build>
第五种:一般情况下需要自己找插件的就这上面几种情况,市面上有些架构有自己的编译插件,比如上面提到的springboot,springboot的编译插件相当简洁,整个spring Boot框架能把能砍掉的繁杂配置步骤全砍了,编译完会有两个结果,用没有后缀的就行
<plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId><configuration><mainClass>com.example.bootweb.BootWebApplication</mainClass></configuration>
</plugin>