序
微服务项目在测试环境通过jenkins自动发布部署时,某个服务编译时出现找不到相关包问题。
错误日志
诱发原因
- 因为项目中存在两个module模块服务相互依赖导致的,基础服务action依赖于引用了全局日志服务log
- 所以在action服务的pom.xml文件中增加日志服务依赖
<dependency>
<groupId>com.xf.log</groupId>
<artifactId>biz-support-log</artifactId>
<version>2.0.0</version>
</dependency>
- 而log日志服务pom.xml文件中引入speingboot与maven打包插件spring-boot-maven-plugin(主要问题诱发原因)
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
知识小补充:
spring-boot-maven-plugin 插件的主要作用是给springboot项目打一个可直接运行的jar包(就是用 java -jar 的方式直接运行)。
要想使用该插件打一个可直接执行的jar包,前提是必须有个带有@SpringBootApplication注解和main方法的启动类
- 在通过发布打包时,编译action基础服务时会把它所需的依赖包括引用的其他服务依赖jar包一起安装下载进行打包到action的jar中,但需要的是log普通打包的jar,不能是log服务可执行的jar,当action服务在实际代码业务中使用了或调用了log服务的代码,那么编译action基础服务时就会找不到log服务中的包路径,导致编译失败
解决方案
- 方案一:修改spring-boot-maven-plugin插件为以下所示
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<classifier>exec</classifier>
</configuration>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
说明:通过修改插件,会生成两个jar包,一个是带有exec的jar包,该jar包就是可执行的jar;一个是原始jar(其他服务引用需要的jar包)
- 如果被依赖的项目只是纯被依赖(或者是不需要打包成可执行jar运行),那么可以直接把spring-boot-maven-plugin依赖直接从pom.xml中删除
思考与疑惑
- 到底是为什么可执行的jar包不能被其他服务使用,并且报错找不到包,普通的jar包和可执行的jar包有什么区别呢?
带着上述疑问,我在社区提问求解惑
提问:
回复:
(大致的意思是因为一个jar包中存在俩个main方法,所以导致的报错)
过后又去请教了其他人回复:两者没有什么大的区别,只是多了一个启动入口方法main,其他没什么区别(可能是我没表述清楚吧,我还是不解,既然是因为main方法多个导致,那为什么会找不到包呢,有点不符合实际啊)
实践解惑
- 将spring-boot-maven-plugin插件3种不同的方式进行打包比对,分别对项目进行以下操作,并查看target文件下生成的jar情况
- pom.xml不引入spring-boot-maven-plugin依赖
- pom.xml引入spring-boot-maven-plugin依赖
生成了2个文件,查看打包日志发现,实际上项目进行了2次打包,第一次是普通打包,第二次通过插件打包并生成可执行jar包,并且将之前的普通jar包改名加上了 .original 格式后缀,自己承袭了普通jar的名称(jar名称不是重点),主要是普通jar包已经不是 .jar格式了,所以调用方服务扫描不到包,就出错了
- 通过上述 解决方案1 修改spring-boot-maven-plugin插件依赖格式
同样生成两个jar包,但这次都是.jar格式的,那么调用方服务就能成功扫描到包,然后编译成功。名称有exec的是可执行jar,另一个是普通jar。图中可看出它们的文件大小根本不在一个量级上,差距很大,可能不仅仅是有无main方法的差别。
- 调用方服务为什么扫描不到可执行jar包?
分别解压上述两个jar包
- biz-support-log-2.1.4.jar内部结构
- biz-support-log-2.1.4-exec.jar内部结构
通过上面比较两者的内部结构完全不一致,调用方服务编译时,只会根据调用时类中导入的包路径进行扫描的,通过查看上述的异常图片和项目中代码,只有普通jar中的路径是一致的。
补充:直接运行的jar,可能内嵌了更多支撑服务能正常运行的组件和容器等,所以不能作为依赖jar进行使用
完结