zoukankan      html  css  js  c++  java
  • 二方包依赖spring boot引发的坑

    问题描述

    应用使用的框架基于spring+webX,代码迭代之后,启动报错。
    image.png

    问题定位

    问题比较

    • 网上搜索相关报错信息,大多数都是提示该类错误:

    Could not open ServletContext resource [/WEB-INF/applicationContext.xml]

    image.png
    一般错误的原因都在该目录下找不到applicationContext.xml文件,在web.xml文件中配置一下就行。

    • 但是本文遇到的问题是:

    Could not open ServletContext resource [/]

    问题解决过程

    • 代码上基本上没有改动框架的配置,都是增加的业务逻辑,初步定位是maven依赖的问题
    • 从master拉新分支(能启动成功),然后将改动之后的maven依赖同步过来,果然,项目启动报了相同的错误。
    • 通过mvn dependency:tree命令,输出不报错分支依赖树和报错分支的依赖树,经过对比,发现在报错的分支中多了和spring-boot相关的启动jar包。
    • 排掉和spring启动相关的包,重新部署,项目启动成功。

    细化分析

    为什么在非spring boot项目中依赖spring boot包,启动报错?
    上诉我们只是将spring boot相关包排掉,但是不清楚具体是哪个jar包造成的影响。

    经过分类排包后定位到是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:
    始作俑者是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就被篡改了。
    在启动日志中看见有这样的内容(下图):这也印证了JerseyWebApplicationInitializer确实被加载了。
    image.png
    当ServletContext初始化完成之后web容器就开始启动了,我们的应用是基于webx的,配置在web.xml中的webx的监听器便开始起作用了。
    WebxContextLoaderListener实现了spring的ContextLoaderListener。它会调用ContextLoader的initWebApplicationContext()方法,而在webx中初始化的是WebxComponentContext(继承自XmlWebApplicationContext)。ContextLoaderListener是使用servletContext来做初始化的,这时已经被修改过了,那个NONE就是这样被传过来的。

    总结

    • 采用最小化原则,不要在二方包中依赖spring boot启动相关的jar包,(spring boot与webx不兼容的)
    • 应该将相关依赖放在根pom的dependencyManagement标签中,让子模块去显示依赖,而不要放在dependencies标签中直接定义
    • 线上部署时应该杜绝SNAPSHOT二方包,采用RELEASE

    参考文章:https://www.cnblogs.com/cishengchongyan/p/6235439.html

  • 相关阅读:
    MongoDB结构划分
    iphone下scrollview图片浏览器小记
    图文详解linux/windows mysql忘记root密码解决方案
    【记】Javascript遍历对象属性的方法
    【jQuery】jQueryUI中的datepicker在overflow下的两点点小小的问题。
    第一个测试文章
    【记】Javascript的正则表达式RegExp
    【记】IE下input标签中的paddingleft和paddingright
    【CSS】关于IE、FireFox中table强制换行的总结
    【DOCTYPE】兼容模式和标准模式
  • 原文地址:https://www.cnblogs.com/cjyboy/p/15492502.html
Copyright © 2011-2022 走看看