Springboot打war包Filter依赖注入为null

        近期Springboot项目需要在国产Web容器上运行,在打完war包启动后出现Filter中注入的bean为null的错误。

        在网上搜了一圈,解决方案如下:

 public void init(FilterConfig filterConfig) throws ServletException {
        ServletContext servletContext = filterConfig.getServletContext();
        WebApplicationContext webApplicationContext = WebApplicationContextUtils.getWebApplicationContext(servletContext);
        if (webApplicationContext != null) {
            this.ramCacheLoader = (RamCacheLoader)webApplicationContext.getBean(RamCacheLoader.class);
        }
    }

        在Filter的init方法中,通过FilterConfig从容器中获取Serverlet上下文ServerletContex,从而获取Springboot上下文,最后从Springboot上下文对象中获取bean。

        解决方案找到了,但是为什么jar包方式可以注入成功,war包方式注入失败的原因还没搞清楚,故做了一番深入的学习,在此记录一下。

        我们在创建Springboot工程时,会依赖 spring-boot-starter-web ,从而可以使用Springboot内置Web容器(默认为Tomcat),通过分析Springboot启动流程,SpringApplication.run 会在打印Banner 后创建通过 createApplicationContext() 方法 ApplicationContext 容器(IOC容器),然后通过 refreshContext(context) 方法,刷新容器,此时会获取嵌入式Servlet容器工厂,由容器工厂创建Servlet,也就是说此时是先创建容器,后创建Serverlet,而 Filter 由Serverlet托管,故此时启动实例化 Filter 时可以获取到bean。

        而打war包时,我们会在依赖中排除内置tomcat:

<!-- 将原来的内置tomcat依赖scope改为provided-->
<!-- 内置tomcat -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-tomcat</artifactId>
    <scope>provided</scope>
</dependency>

        并修改 SpringApplication 启动类:

@SpringBootApplication
public class Application extends SpringBootServletInitializer {
    
    public static void main(String[] args) {
        SpringApplication.run(ZxblogApplication.class, args);
    }
    
    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
        return builder.sources(Application.class);
    }
}

        此时, SpringBootServletInitializer 实例执行onStartup方法的时候会通 createRootApplicationContext 方法来执行run方法,接下来的过程就同以jar包形式启动的应用的run过程一样了,在内部会创建IOC容器并返回,只是以war包形式的应用在创建IOC容器过程中,不再创建Servlet容器了。

        因此,相当于Spring并不会托管Serverlet,自然也就不会托管Filter,Filter也就无法通过@AutoWired注解获取到容器中的bean。

        那么,文章开头的方式为什么可以获取到bean呢?因为init方法中有一个形参 FilterConfig,通过其 getServletContext() 可以获取 ServletContext 对象的引用,从而获取上下文对象,最后通过上下文获取bean, FilterConfig相当于连接Filter和IOC容器的桥梁。

        自己的片面理解,如有错误请指正!

        参考连接:spring boot中servlet启动原理

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值