公司的这种打包启动方式,我简直惊呆了
theme: cyanosis
前言
大家都知道,SpringBoot应用最终会打出一个Fat Jar
, 里面包含了用到的全部依赖,启动也非常简单,java -jar xxx.jar
即可。
但是我们公司打出的最终包,将依赖包挪到了外部,然后启动的时候通过loader.path
指定依赖包的位置,如java -Dloader.path=libs -jar xxxx
的方式启动,也能够启动成功。
这样做最大的一个好处就是如果发现某个依赖出现问题,那么我只需要在libs替换其中某个依赖,影响范围可以减小很多。
那大家是不是很好奇是怎么做到的呢?
打包方式详解
主要是通过两个maven插件打出这样的结构的包。
- spring-boot-maven-plugin
该插件是spring boot
官方提供的一个打包插件,主要用来打出fat jar
,并且提供了支持java -jar xxx.jar
方式启动。 官网地址:https://docs.spring.io/spring-boot/docs/current/maven-plugin/reference/htmlsingle/。
我们需要用这个插件,因为只有它可以打出支持启动的jar,但是打出的包中又不能有依赖,该怎么做呢?如下图:
layout
: 布局方式,这里要选择ZIP
,后面说明原因。-
includes
: 选择包含哪些依赖,这里写了一个不存在的jar,那么也间接实现了不打入其他的依赖。这种方式比较ugly,但是目前没有找到更加合适的方案。 -
maven-assembly-plugin
maven-assembly-plugin插件可以灵活定制打包内容,官网地址:https://maven.apache.org/plugins/maven-assembly-plugin/。
我们现在就是想办法利用该插件抽出我们用到的依赖包,该怎么做呢?
我们现在看下assembly.xml
中的关键配置:
- 可以根据
include
、exclude
属性通过正则灵活的抽取相关依赖到指定的目录下
最终执行mvn clean package
在target目录下得到最终的安装包:
解压该安装包:
打开libs目录:
启动方式解析
现在我们已经按照自己想要的结构打出包了,那如何在启动的时候加载libs
目录中的依赖呢?
前面提到了springboot
插件打出的包是启动的入口,实际上在这个包里面springboot
会自动打入一个引导类org.springframework.boot.loader.Launcher
,它是 Spring Boot
可执行 jar 的主要入口点,它是 Spring Boot jar
文件中的实际 Main-Class
,用于设置适当的 URLClassLoader
并最终调用Spring Boot
项目中定义的 main()
方法。
Launcher
有三个子类(JarLauncher
、WarLauncher
和 PropertiesLauncher
),如果我们打包插件的layout
配置的是ZIP
的方式,它会使用PropertiesLauncher
。
PropertiesLauncher机制说明:
默认情况下,PropertiesLauncher
在 BOOT-INF/lib/
中加载,我们可以通过设置loader.properties
中的loader.path
或 LOADER_PATH
环境变量来增加其它的加载位置。
loader.path
:配置逗号分隔的Classpath
类路径,例如lib,${HOME}/app/lib
,前面的路径优先,类似于 javac 命令中的-classpath
。loader.home
:用于解析loader.path
配置的相对路径,默认是${user.dir}
。
所以,打包成功后,我们可以通过java -jar -Dloader.path=xx1,xx2,public <jarName>.jar
命令来启动程序,这样对应目录下的依赖均会被加载。
总结
这种打包启动方式虽然不常见,但是还是有一定的价值的,特别是在项目组件模块比较多的时候,出现紧急缺陷,可以按需替换包,将影响范围控制到最小。
如果本文对你有帮助,请随手留下一个赞吧。
本文正在参加「金石计划 . 瓜分6万现金大奖」
- 乐观锁思想在JAVA中的实现——CAS
- 一步步带你设计MySQL索引数据结构
- 我总结了写出高质量代码的12条建议
- 工作这么多年,我总结的数据传输对象 (DTO) 的最佳实践
- Spring项目中用了这种解耦模式,经理对我刮目相看
- 大数据HDFS凭啥能存下百亿数据?
- 5个接口性能提升的通用技巧
- 你的哪些SQL慢?看看MySQL慢查询日志吧
- 90%的Java开发人员都会犯的5个错误
- 丧心病狂,竟有Thread.sleep(0)这种写法?
- 为什么更推荐使用组合而非继承关系?
- 一个30岁程序员的觉醒和进击
- 推荐8个提高工作效率的IntelliJ插件
- 公司的这种打包启动方式,我简直惊呆了
- 告别丑陋判空,一个Optional类搞定
- 你不知道的Map家族中的那些冷门容器
- SpringBoot 2.x整合Log4j2日志
- SpringBoot应用自定义logback日志
- 你确定懂了Java中的序列化机制吗
- TO BANK解决方案微服务架构的正确姿势