为什么不要将spring-boot相关依赖打入二方包

摘要:
本文的内容来自于博主的第一个故障排除过程,最后解释了为什么我们不应该在第二方包中包含与spring-boot相关的依赖项。将在线和预分发的war包中的二进制包文件列表输出到两个不同的文件中,然后对两个文本进行比较以找到发起者:framework-sqlanalys-1.0.0-SNAPSHOT包的大小已更改,并添加了一些新的二进制包,如pandora boot和spring boot。在pom中消除了潘多拉引导和弹簧引导后,部署再次成功。也就是说,在为非spring boot应用程序引入spring boot或Pandora boot的两方包之后,将出现上述问题。

 

  本文内容来源于博主一次问题排查的过程,最终说明为什么不要将spring-boot相关依赖打入二方包。

  先介绍一下背景:我们应用是一个标准的spring+webx工程,博主在一次项目发布前为了再次测试一下自己的代码,将分支部署到日常环境中,但是项目启动的时候报错:

  为什么不要将spring-boot相关依赖打入二方包第1张

  第一眼看到这个堆栈后有点懵逼

  第一是上一次部署分支还没问题,距离上次部署自己新增的代码也很简单,不可能写出如此诡异的代码去改变spring的行为。况且从tomcat启动日志来看,报错的时候还根本没有到应用的代码。

  第二是这个错误本身,Could not open ServletContext resource很常见,但是这个错误后面通常都是无法打开一个具体的文件,一般就是工程里(例如autoconfig)配置了一个文件路径,而文件路径不存在。但是,这里的文件路径竟然是NONE。

  •  问题排查及解决过程

  首先是怀疑自己的分支出了什么问题,部署了一下主干,还有这个报错。因为错误堆栈来看是从tomcat过来的,因此猜测有以下解释:

  1. 环境因素(PE有没有对tomcat或pandora做什么事情)
  2. 文件不存在或文件权限有问题(导致path为NONE)
  3. Jar包冲突(原二方包版本变化)或Jar包干扰(新增二方包产生干扰)

  排查过程:

  1. 首先我们怀疑的环境因素导致的,对比了一下日常/预发和线上的环境差异,jdk、tomcat、pandora版本都一样。同时在日常也启动了一遍,也报这个错。如果环境因素导致的不会日常和线上都存在问题吧。看了下邮件也没发现PE有什么动作,这时候还不放心申请了个项目环境跑了一遍还是这个错,如果日常和预发是PE搞了什么鬼那么项目环境完全是一个干净的环境,应该不会产生干扰。因此环境因素基本排除掉了。
  2. 日常和预发的WEB-INF文件都是存在的,同时对比了下线上的WEB-INF文件夹的权限,发现也是完全一样的,因此文件的因素也被排除掉了。
  3. 接下来我们重启了一台线上机器的war包,没有任何报错,这个时候又有点怀疑环境因素,我们将线上机器war包scp到预发机器上,启动没有报错!那么,环境因素可以彻底排除掉了。

  同为主干代码线上war包没问题而日常/预发部署就有问题,问题基本清晰起来了,应该是某个SNAPSHOT二方包引起的问题。

  分别将线上和预发war包里的二方包文件列表输出到两个不同的文件中,然后diff两个文本后发现了始作俑者:

  为什么不要将spring-boot相关依赖打入二方包第2张

  发现framework-sqlanalyse-1.0.0-SNAPSHOT包的大小有所变化,并且新增了pandora-boot及spring-boot等一些新的二方包。

  mvn tree查看了下,pandora-boot和spring-boot果然就是由framework-sqlanalyse引入进来的。在pom中把pandora-boot和spring-boot排掉之后再次部署终于成功了。至此这个问题算是解决了,但是到底是怎么产生的呢?

  • 问题定位

  回到刚刚diff的文件结果,我们发现这并不是一个包的冲突(因为只有framework-sqlanalyse这个包变化了),而是新包产生的干扰。也就是说非spring-boot应用引入了spring-boot或pandora-boot的二方包之后就会产生上述问题。那么这个问题到底是如何产生的?

  首先需要定位到底是哪个包导致的这个问题,经过分类排包后定位到是org.springframework.boot:spring-boot-autoconfigure这个包引起的,但是我们的报错堆栈中并没有org.springframework.boot相关的类。

  spring-boot-autoconfigure这个包用于spring boot自动配置机制,如果在应用中添加了@EnableAutoConfiguration就会触发自动配置,它会根据定义在classpath下的类,自动生成一些Bean,并加载到Spring的Context中。spring boot应用启动类上的@SpringBootApplication便继承自@EnableAutoConfiguration。

  一开始也怀疑是自动配置导致的,但是我们的应用只是一个spring+webx的普通web应用而已,并没有@EnableAutoConfiguration,因此不会触发自动配置,也不会加载embed tomcat。

  后来发现这是来自于spring boot的一个官方issue:https://github.com/spring-projects/spring-boot/issues/5740

  始作俑者是spring-boot-autoconfigure中一个配置类JerseyAutoConfiguration中的内嵌类JerseyWebApplicationInitializer

  @Order(Ordered.HIGHEST_PRECEDENCE)
  public static final class JerseyWebApplicationInitializer implements WebApplicationInitializer {
    @Override
    public void onStartup(ServletContext servletContext) throws ServletException {
      // We need to switch *off* the Jersey WebApplicationInitializer because it
      // will try and register a ContextLoaderListener which we don't need
      servletContext.setInitParameter("contextConfigLocation", "<NONE>");
    }
  }

  我们知道,继承了WebApplicationInitializer的类都会被应用加载,原因就在于SpringServletContainerInitializer,他会实例化classpath下所有继承了WebApplicationInitializer的类,并且会触发每个WebApplicationInitializer的onStartup方法。这样,servletContext就被篡改了。

  在启动日志中看见有这样的内容:INFO: Spring WebApplicationInitializers detected on classpath: [org.springframework.boot.autoconfigure.jersey.JerseyAutoConfiguration$JerseyWebApplicationInitializer@155b6f9d]  这也印证了JerseyWebApplicationInitializer确实被加载了。

  当ServletContext初始化完成之后web容器就开始启动了,我们的应用是基于webx的,配置在web.xml中的webx的监听器便开始起作用了。

  WebxContextLoaderListener实现了spring的ContextLoaderListener。它会调用ContextLoader的initWebApplicationContext()方法,而在webx中初始化的是WebxComponentContext(继承自XmlWebApplicationContext)。ContextLoaderListener是使用servletContext来做初始化的,这时已经被修改过了,那个NONE就是这样被传过来的。

  •  总结

  至此这个问题已经搞清楚了,最后总结一下上面这个case有以下几点:

  1. 除非万不得已,今后线上部署时应该杜绝SNAPSHOT二方包,一方面减少下次部署隐患,另一方面排查问题时也可以排除不必要的干扰。
  2. 不要将spring boot相关依赖打入二方包中,如果webx应用使用了该二方包会必现上述问题,目前spring boot与webx依然是不兼容的。
  3. 在项目工程开发时,spring boot应用的正确依赖姿势应该是这样的:根pom中应该将spring-boot及pandora-boot相关依赖放在dependencyManagement标签中,让子模块去显示依赖,而不要放在dependencies标签中污染client包。

免责声明:文章转载自《为什么不要将spring-boot相关依赖打入二方包》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇ER图向关系模型的转换遵循原则(转载)hexo干货系列:(六)hexo提交搜索引擎(百度+谷歌)下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

随便看看

Kafka监控工具——Kafka-Eagle

Kafka监控工具官网https://www.kafka-eagle.org/是什么KafkaEagle是一款用于监控和管理ApacheKafka的完全开源系统,目前托管在Github,由笔者和一些开源爱好者共同维护。而且,在使用消费者API时,尽量#客户端KafkaAPI版本和Kafka服务端的版本保持#一致性。...

uniapp安卓真机调试提示检测不到手机【解决办法】

以下是具体的解决方案:步骤1:打开、查找、单击并单击7次或更多次,以允许开发人员进行选择。...

[转]从minio中读取文件流进行下载文件

本文转自:https://blog.csdn.net/ZHANGLIZENG/article/details/82892678一、获取Minio连接publicstaticStringminioUrl;publicstaticStringminioUsername;publicstaticStringminioPassword;@Value("${syste...

2022年可用QQ机器人框架

4.小李子机器人官网:https://xiaolz.cn评估:支持多个Q登录和论坛似乎是目前最活跃的。它支持许多api,可以满足许多需求。没有限制,但有很多错误。...

以『公众号』为例,手把手教你爬取PC端数据

“appmsgext_url=origin_url+”__biz={}&mid={}&sn={}&idx={}&appmsg_token={}&x5=1“.formatcontent=requests.post.json()打印打印可以看到帖子已成功发送,并提取相应的阅读号、点赞号和观看号。5。同一个公众号被扩展。如果...

Windows10 解除公司换壁纸限制

桌面点右键,属性,就可以改自己喜欢的桌面背景了。...