之所以研究 SpringBoot 项目的打包优化,是最近在学习 SpringCloud 微服务,写了一个仅提供 eureka 注册服务中的功能的 springboot 项目,打包后 50M,一考虑到实际上或许会部署多个应用到同一台服务器,那里面重复 jar 包就很占很大一部分
在日常工作里,仅仅修复了一个 bug,改动了几个文件,就得重新打包,然后走向日葵给现场提供一个近 100M 的包,文件传输的速度实在是太拉垮了
项目环境
maven: 3.5.9
springboot: 2.3.8.RELEASE
java: 1.8
复制代码
方案 1
打包插件 spring-boot-maven-plugin
通过 spring starter project 创建项目时会默认带有这个插件,并且会自动排除 lombok 的依赖,我们需要做的就是添加其他配置
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<!-- 指定该Main Class为全局的唯一入口 -->
<mainClass>com.wx.demo.EurekaServiceApplication</mainClass>
<!--把第三方jar包打入jar -->
<includeSystemScope>true</includeSystemScope>
<fork>true</fork>
<!-- 设置为ZIP,此模式下spring-boot-maven-plugin会将Manifest.MF文件中的Main-Class设置为org.springframework.boot.loader.PropertiesLauncher -->
<layout>ZIP</layout>
<includes>
<!--去除在生产环境中不变的依赖 -->
<!--<excludeGroupIds> -->
<!--org.springframework.boot -->
<!--</excludeGroupIds> -->
<include>
<!-- 排除所有Jar -->
<groupId>nothing</groupId>
<artifactId>nothing</artifactId>
</include>
</includes>
</configuration>
<executions>
<execution>
<goals>
<goal>repackage</goal>
<!--可以把依赖的包都打包到生成的Jar包中 -->
</goals>
</execution>
</executions>
</plugin>
复制代码
依赖相关的处理插件 maven-dependency-plugin
添加插件 ,用途为将项目中用到的 jar 包,复制到指定的路径
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<executions>
<execution>
<id>copy</id>
<phase>package</phase>
<goals>
<goal>copy-dependencies</goal>
</goals>
<configuration>
<!-- 将 jar 包复制到 mvn 项目的构建路径下,例如 项目名/target/libs/ 目录下-->
<!-- <outputDirectory>${project.build.directory}/libs</outputDirectory> -->
<!-- 将 jar 放到固定的位置,方便管理 -->
<outputDirectory>C:/Users/wangbin1/Desktop/libs</outputDirectory>
</configuration>
</execution>
</executions>
</plugin>
复制代码
测试插件 maven-surefire-plugin
maven-surefire-plugin
是 maven 里执行测试用例的插件,不显示配置就会用默认配置。这个插件的surefire:test
命令会默认绑定 maven 执行的test
阶段。
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<!-- 跳过打包单元测试 -->
<skipTests>true</skipTests>
</configuration>
</plugin>
复制代码
缺点:在运行 jar 包的时候,我们需要额外指定运行参数 -Dloader.path=libs/
,就是告诉虚拟机需要去哪里加载项目中关联的 jar
方案 2
二号打包插件 maven-jar-plugin
替换插件 spring-boot-maven-plugin
,在插件里指明 jar 包运行时需要去哪里加载依赖的 jar
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<archive>
<manifest>
<addClasspath>true</addClasspath>
<!-- 运行时需要额外加载读取 jar 包的位置 -->
<classpathPrefix>libs/</classpathPrefix>
<mainClass>com.wx.demo.EurekaServiceApplication</mainClass>
</manifest>
</archive>
</configuration>
</plugin>
复制代码
如代码中配置的路径为 libs/
,这是一个相对路径,后续我们运行 eureka.jar
包时,就需要将 eureka.jar 和 libs/
放在同级目录下
|- libs
|- a.jar
|- b.jar
|- xxx
|- eureka.jar
复制代码
或者,将 libs 包放到 jdk 环境下,如我本机的 jdk 路径为 C:\Program Files\Java\jdk1.8.0_181
注意点:在打包插件中,<classpathPrefix>
配置的是相对路径,在依赖管理的插件中,<outputDirectory>
配置的是绝对路径
更新
在实际使用的过程中,发现需要对打包的应用进行名称指定
如果是使用 spring-boot-maven-plugin
,可以通过configuration.finalName
来指定,但是因为需要使用maven-jar-plugin
进行打包,查阅后发现有提供相关配置项configuration.archive.manifest.packageName
,遗憾的是打包的文件名还是默认值
最后的解决方案就是,使用 pom 文件的节点参数配置 build.finalName
,成功
后续
因为是在学习微服务,将 注册中心,生产者,消费者 3 个 springboot 项目打包后,需要通过 cmd 运行起来,每次都手动新开 cmd 就很麻烦,网上查找到相关资料
在当前 cmd 中新开一个 cmd 命令行
新开一个 cmd 命令行,并执行一条命令
start cmd /k java -jar eureka-service-0.0.1.jar
复制代码
/k 和 /C 的区别
/k 命令执行完后,窗口不会关闭
/C 命令执行完后,窗口会关闭
复制代码
新开命令行,并在后台执行命令,将运行的数据输出到指定文件
执行一条命令,并将执行的结果输出到指定路径的文件中
覆盖写入 > filepath
追加写入 >> filepath
> filepathh 2>&1
,2>&1,错误定向到输出,标准输入又追加到 file 中,所以错误和 cmd 输出都追加到 file
cmd /c start /b java -jar > "d:/log/autopack/网页程序运行监控.log" 2>&1 "AutoPackageLine-1.jar"
复制代码
关闭指定的进程
/T 终止指定的进程和由它启用的子进程。
/F 指定强制终止进程。
/IM imagename 指定要终止的进程的映像名称。通配符 '*'可用来
示例代码,关闭全部的 java 进程
taskkill -t -f /im java
复制代码
评论