springboot 项目打包优化(核心 class 与依赖 jar 分离)

1,857 阅读3分钟

这是我参与8月更文挑战的第1天,活动详情查看:8月更文挑战

之所以研究 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> 配置的是绝对路径

需要大佬们支一个招,我尝试在 <classpathPrefix> 配置绝对路径为/${env.JAVA_HOME}/three-part-libs/eureka/ 后,启动应用会报错Exception in thread "main" java.lang.NoClassDefFoundError: org/springframework/boot/SpringApplication

这么配置的一个目的就是,我们直接吧项目需要的 jar 包,和 jdk 放一块,后续部署 server.jar 的时候就不需要考虑太多的事情

更新

在实际使用的过程中,发现需要对打包的应用进行名称指定

如果是使用 spring-boot-maven-plugin,可以通过configuration.finalName 来指定,但是因为需要使用maven-jar-plugin 进行打包,查阅后发现有提供相关配置项configuration.archive.manifest.packageName,遗憾的是打包的文件名还是默认值

最后的解决方案就是,使用 pom 文件的节点参数配置 build.finalName,成功

后续

因为是在学习微服务,将 注册中心,生产者,消费者3个 springboot 项目打包后,需要通过 cmd 运行起来,每次都手动新开 cmd 就很麻烦,网上查找到相关资料

在当前 cmd 中新开一个 cmd 命令行

start 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

注:参照 csdn 博客成功实现 SpringBoot打包优化


原创文章,未经允许,禁止转载

-- by 安逸的咸鱼