问题背景
maven-历史版本下载
/dist/maven/maven-3/
Spring Boot 项目一般会依赖较多的包括 Spring 在内的第三方 jar 包,直接打可运行 jar 包,文件大小往往会达到100M甚至更大;
在重复部署测试或者生产环境的时候,每次都要上传包含所有依赖 jar 包的可运行 jar 文件,效率比较低;
期望目标
maven 配置,Spring Boot 项目打包时,只包含自己开发的代码,大小仅100kb,所依赖的第三方 jar 则复制到指定的目录下;
这样我们可以只需要上传一次第三方 jar,每次修改代码重新部署时,只上传仅包含我们开发代码的 jar 文件,大大提高了部署效率。
解决方法
maven 的 pom 配置如下,${} 变量根据自己的项目进行替换,第三方 jar 指定到 target/lib 目录下:
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>${}</source>
<target>${}</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
<plugin>
<groupId></groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<!-- 跳过单元测试 -->
<skipTests>true</skipTests>
</configuration>
</plugin>
<plugin>
<groupId></groupId>
<artifactId>maven-dependency-plugin</artifactId>
<executions>
<!-- 复制第三方 jar 到项目目录下的 target/lib/ 下 -->
<execution>
<goals>
<goal>copy-dependencies</goal>
</goals>
<configuration>
<outputDirectory>${}/lib</outputDirectory>
<excludeScope>provided</excludeScope>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId></groupId>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<archive>
<manifest>
<!-- 指定 Spring Boot 启动类,实际测试中必须 -->
<mainClass>${}</mainClass>
<!-- 将所有第三方 jar 添加到项目 jar 的 文件中,这样运行 jar 时依赖包才能被加载 -->
<addClasspath>true</addClasspath>
<!-- 指定复制第三方 jar 的目标目录为 target/lib/-->
<classpathPrefix>./lib/</classpathPrefix>
</manifest>
</archive>
</configuration>
</plugin>
<plugin>
<groupId></groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<!-- repackage 时排除掉 第三方依赖 jar 文件,我们的可运行 Spring Boot 的 jar 文件瞬间变小 ^_^ -->
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
<configuration>
<includes>
<include>
<groupId>nothing</groupId>
<artifactId>nothing</artifactId>
</include>
</includes>
</configuration>
</plugin>
</plugins>
附录: Maven几个常用的maven插件
简介
我们使用maven做一些日常的工作开发的时候,无非是想利用这个工具带来的一些便利。比如依赖管理,方便我们打包和部署运行。这里几个常见的插件就是和这些工程中常用的步骤相关。
- maven-compile-plugin
这个插件就如同名字所显示的这样,用来编译源代码的。最开始碰到这个插件是在于有的时候我们下载了一些工程需要编译的时候,比如我们输入命令:mvn install ,但是系统编译的时候报错了,错误的信息如下:
[ERROR] Failed to execute goal :maven-compiler-plugin:2.0.2:compile (default-compile) on project springJMS: Compilation failure: Compilation failure:
[ERROR] /home/frank/programcode/SpringJMSSample/src/main/java/huangbowen/net/jms/:[6,1] error: annotations are not supported in -source 1.3
[ERROR]
[ERROR] (use -source 5 or higher to enable annotations)
[ERROR] /home/frank/programcode/SpringJMSSample/src/main/java/net/:[5,7] error: static import declarations are not supported in -source 1.3
[ERROR] -> [Help 1]
[ERROR]
[ERROR] To see the full stack trace of the errors, re-run Maven with the -e switch.
[ERROR] Re-run Maven using the -X switch to enable full debug logging.
[ERROR]
[ERROR] For more information about the errors and possible solutions, please read the following articles:
从错误显示的信息我们就可以看出,这是因为编译的时候是默认用的javac 1.3版本的,太老了不支持代码里的特性。为了修改这个问题,我们需要设置编译器的版本。解决这个问题的办法也比较简单,就是直接在后面的插件部分增加如下的插件,比如如下部分,将编译器的版本设定为1.6:
<build>
<plugins>
<plugin>
<groupId></groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.3.2</version>
<configuration>
<source>1.6</source>
<target>1.6</target>
</configuration>
</plugin>
</plugins>
</build>
- exec-maven-plugin
我们写一些java console相关的程序时,比较头疼的一点就是真正要通过命令行将打包后的程序执行起来还是比较麻烦的。我们需要在命令行里敲如下的命令:java -cp .jar:.jar:/*/ 。因为要将classpath目录以及引用的类库都加入进来,并指定运行的入口,这样子每次用手工的方式来处理实在是太繁琐也比较容易出错。所以一种办法就是利用这个插件,通过一些基本的配置,我们可以执行起代码来的时候很方便。一个典型的配置如下:
<plugin>
<groupId></groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>1.2.1</version>
<executions>
<execution>
<goals>
<goal>java</goal>
</goals>
</execution>
</executions>
<configuration>
<mainClass></mainClass>
</configuration>
</plugin>
如果我们运行的时候需要提供一些输入的参数,也可以通过configuration的元素里添加。这样后续要执行这个程序时,我们只需要在命令行执行如下命令:mvn exec:java ,然后程序就可以运行起来了。
- maven-dependency-plugin
这个插件可以做什么事情呢?由goal标签指定
copy:将指定坐标对应的jar包拷贝到指定目录
unpack:将指定坐标对应的jar包解压到指定目录
3.1 copy
下述配置在打包阶段会将junit包拷贝到项目的target/alternateLocation目录下
<build>
<plugins>
<plugin>
<groupId></groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>3.2.0</version>
<executions>
<execution>
<id>copy</id>
<phase>package</phase>
<goals>
<goal>copy</goal>
</goals>
</execution>
</executions>
<configuration>
<artifactItems>
<artifactItem>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<type>jar</type>
<overWrite>false</overWrite>
<outputDirectory>${}/alternateLocation</outputDirectory>
</artifactItem>
</artifactItems>
</configuration>
</plugin>
————————————————
3.2 copy-dependencies
和copy命令的区别是,copy是拷贝指定坐标的jar包,而copy-dependencies则是拷贝项目依赖的所有jar包,具体用法如下
<plugin>
<artifactId>maven-dependency-plugin</artifactId>
<executions>
<execution>
<phase>install</phase>
<goals>
<goal>copy-dependencies</goal>
</goals>
<configuration>
<outputDirectory>${}/lib</outputDirectory>
</configuration>
</execution>
</executions>
</plugin>
从上面的配置里我们可以看到,插件的执行被配置到install这个阶段,当然也可以是 package 阶段
这样,当我们执行命令:mvn clean install 的时候,会发现对应的target目录里生成了对应的jar包和依赖包。
3.3 unpack
unpack命令可以将指定的jar包解压到指定的目录,需要注意的是,如果指定的触发阶段为compile,那么解压之后的内容会一起打包到当前项目中,而如果是package则不会,它只会打包自己项目内容
<plugin>
<groupId></groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>3.2.0</version>
<executions>
<execution>
<!-- 为该操作定义一个名字 -->
<id>unpack</id>
<!-- 该操作在生命周期的那个阶段触发 -->
<phase>compile</phase>
<goals>
<!-- 插件的具体操作,这里只介绍4种-->
<goal>unpack</goal>
</goals>
<!-- 操作的配置 -->
<configuration>
<!-- 配置 -->
<artifactItems>
<!-- 具体配置,此处一般是针对某个坐标的具体配置 -->
<artifactItem>
<!-- 指定坐标 -->
<groupId></groupId>
<artifactId></artifactId>
<version>1.0-SNAPSHOT</version>
<type>jar</type>
<overWrite>true</overWrite>
<!-- 输出路径 -->
<outputDirectory>${}/classes</outputDirectory>
<!-- 坐标对应的jar包的名称 -->
<destFileName>-1.</destFileName>
<!-- 操作的内容 -->
<includes>**/*.html,**/*.js</includes>
<!-- 排除的内容 -->
<excludes>**/*</excludes>
</artifactItem>
</artifactItems>
</configuration>
</execution>
</executions>
</plugin>
3.4 unpack-dependencies
和unpack命令的区别是,unpack是解压指定坐标的jar包,而unpack-dependencies则是解压项目依赖的所有jar包,具体用法如下
<plugin>
<groupId></groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>3.2.0</version>
<executions>
<execution>
<id>unpack-dependencies</id>
<phase>package</phase>
<goals>
<goal>unpack-dependencies</goal>
</goals>
<configuration>
<includes>**/*.class</includes>
<excludes>**/*.properties</excludes>
<outputDirectory>${}/alternateLocation</outputDirectory>
<overWriteReleases>false</overWriteReleases>
<overWriteSnapshots>true</overWriteSnapshots>
</configuration>
</execution>
</executions>
</plugin>
4-1. maven-surefire-plugin 打包时跳过单元测试
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.6</version>
<configuration>
<skip>true</skip>
</configuration>
</plugin>
同: mvn package -=true
4-2. 如果单元测试中有输出中文,eclipse的控制台里中文可能会变成乱码输出,也可以通过这个插件解决,参考配置:
<plugin>
<groupId></groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.16</version>
<configuration>
<forkMode>once</forkMode>
<argLine>-=UTF-8</argLine>
</plugin>
- maven-resource-plugin 设置资源文件的编码方式
<plugin>
<groupId></groupId>
<artifactId>maven-resources-plugin</artifactId>
<version>2.4.3</version>
<executions>
<execution>
<phase>compile</phase>
</execution>
</executions>
<configuration>
<encoding>${}</encoding>
</configuration>
</plugin>
- maven-assembly-plugin
有时候我们需要将项目依赖抽出来单独打包,或者将项目里面的html、js等静态资源抽取出来打包,就需要用到这个插件了。插件的使用如下
<plugin>
<groupId></groupId>
<artifactId>maven-assembly-plugin</artifactId>
<version>3.1.0</version>
<executions>
<execution>
<!-- 操作名,自己指定 -->
<id>assembly</id>
<!-- 操作触发的阶段 -->
<phase>package</phase>
<goals>
<!-- 只执行一次-->
<goal>single</goal>
</goals>
<configuration>
<!-- 自己指定的名字,和配置文件中的id标签对应 -->
<finalName>html</finalName>
<!-- 配置文件的位置和名字(与)的相对路径-->
<descriptors></descriptors>
</configuration>
</execution>
</executions>
</plugin>
除了需要在pom中配置上述内容外,还需要引入一个配置文件(名字由自己指定)
<assembly xmlns="/ASSEMBLY/2.1.0"
xmlns:xsi="http:///2001/XMLSchema-instance"
xsi:schemaLocation="/ASSEMBLY/2.1.0 /xsd/assembly-2.1.">
<id>html</id>
<formats>
<!-- 生成一个zip文件 -->
<format>zip</format>
</formats>
<fileSets>
<fileSet>
<!-- 从编译后的文件中拷贝 -->
<directory>${}/classes</directory>
<!-- 拷贝到的文件存放的路径 -->
<outputDirectory></outputDirectory>
<useDefaultExcludes>true</useDefaultExcludes>
<excludes>
<!-- 哪些文件不拷贝 -->
<exclude>**/*.log</exclude>
<exclude>**/${}/**</exclude>
</excludes>
</fileSet>
</fileSets>
</assembly>