背景
近期有个SpringBoot的项目需要频繁更新,但是每次上传到服务器上几十MB,实在是花时间,所以打算优化打包方案,将第三方依赖外置
流程
- 首先使用SpringBoot打包插件将第三方排除,但是一些版本号同步更新的本地模块依赖需要放到一个jar中
- 使用maven dependency插件将第三方依赖复制到构建目录中
- 使用maven过滤功能实现一个启动脚本
- 使用assembly打包一个完整版,包括boot jar,第三方依赖,启动脚本
- 第一次部署使用完整版,后续更新只需要上传boot jar就行了
实现方法
首先在 resource 目录中准备一个脚本
内容如下
1java -Dloader.path=lib/ -Dfile.encoding=utf-8 -jar @project.build.finalName@.jar 2
其中 @project.build.finalName@ 是最后生成的可执行jar的文件名 path指定第三方依赖目录
其次修改pom文件如下
1 <build> 2 <resources> 3 <resource> 4 <!-- 启用maven过滤,主要为脚本做准备 --> 5 <directory>src/main/resources</directory> 6 <filtering>true</filtering> 7 </resource> 8 </resources> 9 10 <finalName>${project.artifactId}-${project.version}-${spring.active}</finalName> 11 12 <plugins> 13 <plugin> 14 <groupId>org.springframework.boot</groupId> 15 <artifactId>spring-boot-maven-plugin</artifactId> 16 <configuration> 17 <mainClass>xxx.Application</mainClass> 18 19 <layout>ZIP</layout> 20 <executable>true</executable> 21 <includes> 22 <!-- 以下为需要打包到jar中的本地模块依赖,主要是版本号需要更新,如果放到第三方依赖中,可能会出现多个版本 --> 23 <include> 24 <groupId>xxx.xxx</groupId> 25 <artifactId>upload-starter</artifactId> 26 </include> 27 <include> 28 <groupId>xxx.xxx</groupId> 29 <artifactId>pay</artifactId> 30 </include> 31 <include> 32 <groupId>${project.parent.groupId}</groupId> 33 <artifactId>swagger-starter</artifactId> 34 </include> 35 </includes> 36 37 </configuration> 38 </plugin> 39 40 <plugin> 41 <groupId>org.apache.maven.plugins</groupId> 42 <artifactId>maven-dependency-plugin</artifactId> 43 <executions> 44 <execution> 45 <id>copy-dependencies</id> 46 <phase>package</phase> 47 <goals> 48 <goal>copy-dependencies</goal> 49 </goals> 50 <configuration> 51 <!-- 输出的第三方依赖位置 --> <outputDirectory>${project.build.directory}/lib</outputDirectory> 52 <overWriteReleases>false</overWriteReleases> 53 <!-- 此处排除需要打到boot jar中的本地模块依赖 --> 54 <excludeGroupIds> 55 ${project.parent.groupId},xxx.xxx 56 </excludeGroupIds> 57 </configuration> 58 </execution> 59 </executions> 60 </plugin> 61 62 <plugin> 63 <groupId>org.apache.maven.plugins</groupId> 64 <artifactId>maven-assembly-plugin</artifactId> 65 <configuration> 66 <descriptors> 67 <descriptor>assembly.xml</descriptor> 68 </descriptors> 69 </configuration> 70 <executions> 71 <execution><!-- 配置执行器 --> 72 <id>make-assembly</id> 73 <phase>package</phase><!-- 绑定到package生命周期阶段上 --> 74 <goals> 75 <goal>single</goal><!-- 只运行一次 --> 76 </goals> 77 78 <!-- <configuration>--> 79 <!-- <finalName>${project.name}</finalName>--> 80 81 <!-- <descriptor>src/main/assembly.xml</descriptor><!–配置描述文件路径–>--> 82 <!-- </configuration>--> 83 </execution> 84 </executions> 85 </plugin> 86 </plugins> 87 </build>
在 pom.xml 同级目录创建 assembly.xml
内容如下
1<assembly> 2 <id>release</id> 3 <formats> 4 <format>zip</format><!--打包的文件格式,也可以有:war zip--> 5 </formats> 6 <!--tar.gz压缩包下是否生成和项目名相同的根目录--> 7 <includeBaseDirectory>false</includeBaseDirectory> 8 9 <!-- 如果使用这个,也可以不使用maven-dependency插件 --> 10<!-- <dependencySets>--> 11<!-- <dependencySet>--> 12<!-- <!–是否把本项目添加到依赖文件夹下–>--> 13<!-- <useProjectArtifact>true</useProjectArtifact>--> 14<!-- <outputDirectory>lib</outputDirectory>--> 15<!-- <!–将scope为runtime的依赖包打包–>--> 16<!-- <scope>runtime</scope>--> 17<!-- </dependencySet>--> 18<!-- </dependencySets>--> 19 <fileSets> 20 <fileSet> 21 <directory>${project.build.directory}/lib</directory> 22 <outputDirectory>/lib</outputDirectory> 23 </fileSet> 24 </fileSets> 25 <files> 26 <file> 27 <source>target/${build.finalName}.jar</source> 28 <outputDirectory>/</outputDirectory> 29 </file> 30 <file> 31 <!-- 此处将脚本复制两份,分别对应类unix和windows系统,注意,maven过滤之后的文件在target目录下 --> <source>${project.build.directory}/classes/start.sh</source> 32 <outputDirectory>/</outputDirectory> 33 <destName>start.bat</destName> 34 </file> 35 <file> 36 <source>${project.build.directory}/classes/start.sh</source> 37 <outputDirectory>/</outputDirectory> 38 <destName>start.sh</destName> 39 </file> 40 </files> 41</assembly> 42 43
最终效果

可以很明显的看出两个方式打包的大小差异
完整版的目录结构 