开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第1天,点击查看活动详情
开篇
最近遇到这样一个需求:
在我们系统中集成另一家公司(简称A公司)的日志系统,我看了A公司的日志系统对接文档,其实很简单只需要引入一个jar包以及一个logback配置文件文件。
心想这还不简单,分分钟的事,分分钟弄好后又可以摸鱼做其他任务了。
如果没有意外的话,意外就出现了。领导给了我一个前提:不能在自己项目中引入A公司的任何配置!也就是说,不能加入jar包以及配置文件。
项目使用的是springboot,最终运行的环境是k8s或docker。A公司购买了我们的服务,最终要求运行环境为docker。
加载Jar
不能在项目中引入jar的意思是不能在项目的gradle中加入相关依赖,那只能看看怎么把jar从其他地方加载进来。
当时想到了2种方案:
- 自己写个类加载器,加载指定目录的jar包。
- 反正是在docker运行,直接把jar扔到jre的ext目录下。
感觉2种方案都不太好,先摸个鱼冷静下,仔细想想。
先看下目前项目在docker中的运行信息
其中有3个值引起了我的注意:
CLASS-PATH、BOOT-CLASS-PATH、LIBRAY-PATH。
CLASS-PATH对应的是springboot生成的fatjar。
BOOT-CLASS-PATH对应的是jdk的一些路径。
LIBRAY-PATH对应的是系统一些路径。
那么我是不是可以把自己jar的路径想办法拼接到这些路径后面呢?
Boot-Class-Path
这是官方文档上对Boot-Class-Path的说明:
A list of paths to be searched by the bootstrap class loader.
Paths represent directories or libraries (commonly referred to as JAR or zip libraries on many platforms).
These paths are searched by the bootstrap class loader after the platform specific mechanisms of locating a class have failed.
简单的看了一下,意思是说 bootstrap class loader会扫描加载这个路径的目录和文件。
经过一番研究发现 Xbootclasspath这个参数可以设置这个路径。
Xbootclasspath
以下是对应Xbootclasspath的几种使用说明:
-Xbootclasspath:完全替换基本的 Java class 搜索路径(不常用)-Xbootclasspath/p:将 classpath 添加在核心class搜索路径前面(可能冲突)-Xbootclasspath/a:将classpath添加在核心class搜索路径后面(常用)
加载jar的基本思路有了,再看下如何加载jar包外的logback配置文件。
加载额外logback文件
这个比较简单,在启动jar时通过命令行指定要使用的配置文件路径就好了。即:-Dlogging.config=/path/to/logback.xml
整合实现
现在加载jar和logback配置文件的思路都通了,那就开始验证吧。
启动docker镜像
docker run -it \
-v /data/javacub/resouces:/home/resouces \
-e JAVA_TOOL_OPTIONS="-Xbootclasspath/a:/home/resouces -Dlogging.config=/home/resouces/logback-spring.xml" \
-p 8000:8000 \
ee8438b63bb8
遗憾的是,没有成功报错了,看错误日志是日志需要的jar并没有加载进来。
难道是Xbootclasspath没有生效吗?又查了一些资料说,Xbootclasspath需要到具体的jar包,不能是目录,这是jdk8的一个bug。
继续修改,还是提示报错,不过错误已经变了是缺少jar包,又把需要的jar一起加上。终于运行起来了。
到这里就结束了吗?
不,感觉执行命令有点长,看能否缩短些。
既然bootstrap class loader会扫描加载Boot-Class-Path路径的东西,那么logback-spring.xml也在这个路径里,那是不是可以不用-Dlogging.config参数指定了呢?
实验证明是肯定的。
结束
到此,SpringBoot加载额外jar包和配置文件功能已经实现,又可以继续摸鱼啦~~