Spring:代理Filter:DelegatingFilterProxy原理和作用

简介: Spring:代理Filter:DelegatingFilterProxy原理和作用


DelegatingFilterProxy就是一个对于servlet filter的代理,用这个类的好处主要是通过Spring容器来管理servlet filter的生命周期

  • 还有就是如果filter中需要一些Spring容器的实例,可以通过spring直接注入
  • 另外读取一些配置文件这些便利的操作都可以通过Spring来配置实现。


Spring web在设计的时候考虑到某些功能的实现是通过Filter来拦截进行实现的,如果直接的简单的实现几个Filter好像也不是不可以(平时我们就是这么用的),但是Spring框架最核心的是IOC容器,和Spring框架最好的实现就是将要实现的Filter功能注册到IOC容器的一个Bean,这样就可以和Spring IOC容器进行完美的融合,所以Spring Web设计了DelegatingFilterProxy。

本质上来说DelegatingFilterProxy就是一个Filter,其间接实现了Filter接口,但是在doFilter中其实调用的从Spring 容器中获取到的代理Filter的实现类delegate。


DelegatingFilterProxy原理:

1、DelegatingFilterProxy根据targetBeanName从Spring 容器中获取被注入到Spring 容器的Filter实现类,在DelegatingFilterProxy配置时一般需要配置属性targetBeanName

@Override
protected void initFilterBean() throws ServletException {
  synchronized (this.delegateMonitor) {
    if (this.delegate == null) {
      // If no target bean name specified, use filter name.
                        //当Filter配置时如果没有设置targentBeanName属性,则直接根据Filter名称来查找
      if (this.targetBeanName == null) {
        this.targetBeanName = getFilterName();
      }
      // Fetch Spring root application context and initialize the delegate early,
      // if possible. If the root application context will be started after this
      // filter proxy, we'll have to resort to lazy initialization.
      WebApplicationContext wac = findWebApplicationContext();
      if (wac != null) {
                                //从Spring容器中获取注入的Filter的实现类
        this.delegate = initDelegate(wac);
      }
    }
  }
}
protected Filter initDelegate(WebApplicationContext wac) throws ServletException {
    //从Spring 容器中获取注入的Filter的实现类
    Filter delegate = wac.getBean(getTargetBeanName(), Filter.class);
    if (isTargetFilterLifecycle()) {
      delegate.init(getFilterConfig());
    }
    return delegate;
  }


2、在DelegatingFilterProxy的实现方法doFilter中,其实最终调用的是委派的类delegate

@Override
protected void initFilterBean() throws ServletException {
  synchronized (this.delegateMonitor) {
    if (this.delegate == null) {
      // If no target bean name specified, use filter name.
                        //当Filter配置时如果没有设置targentBeanName属性,则直接根据Filter名称来查找
      if (this.targetBeanName == null) {
        this.targetBeanName = getFilterName();
      }
      // Fetch Spring root application context and initialize the delegate early,
      // if possible. If the root application context will be started after this
      // filter proxy, we'll have to resort to lazy initialization.
      WebApplicationContext wac = findWebApplicationContext();
      if (wac != null) {
                                //从Spring容器中获取注入的Filter的实现类
        this.delegate = initDelegate(wac);
      }
    }
  }
}
protected Filter initDelegate(WebApplicationContext wac) throws ServletException {
    //从Spring 容器中获取注入的Filter的实现类
    Filter delegate = wac.getBean(getTargetBeanName(), Filter.class);
    if (isTargetFilterLifecycle()) {
      delegate.init(getFilterConfig());
    }
    return delegate;
  }


总结:Spring web通过提高DelegatingProxyFilter类给开发者提供了便利

 

DelegatingFilterProxy运用

需求

在springboot中 使用了filter, 并且注入了业务工具类(APIUtil ),但注入是null

所以问题就来了:springboot中使用filter时注入bean为null的解决办法

其实Spring中,web应用启动的顺序是:listener->filter->servlet,先初始化listener,然后再来就filter的初始化,再接着才到我们的dispathServlet的初始化


解决办法1:

public class TokenAuthFilter implements Filter {
    private final static Logger log = LoggerFactory.getLogger(TokenAuthFilter.class);
    @Autowired
    private APIUtil apiUtil;
}

新增一个config类,用来手工创建filter的bean, 例如:

@Configuration
public class WebConfig {
  @Bean
    public Filter tokenAuthFilter() {
        return new TokenAuthFilter();
    }
    /**
     * 注册filter,统一处理api开头的请求
     * @return FilterRegistrationBean
     */
    @Bean
    public FilterRegistrationBean tokenAuthFilterRegistration() {
        FilterRegistrationBean registration = new FilterRegistrationBean();
        // DelegatingFilterProxy把servlet 容器中的filter同spring容器中的bean关联起来
        registration.setFilter(new DelegatingFilterProxy("tokenAuthFilter"));
        registration.addUrlPatterns("/api/*");
        registration.setName("tokenAuthFilter");
        registration.setOrder(1);
        return registration;
    }
}


解决办法2:

过滤器是servlet规范中定义的,并不归spring容器管理,也无法直接注入spring中的bean(会报错)

初始化时通过spring上下文获取,进行bean的初始化

@Override
public void init(FilterConfig filterConfig) throws ServletException {
    ApplicationContext context = WebApplicationContextUtils.getWebApplicationContext(filterConfig.getServletContext());
    RedisTemplate demoBean = (RedisTemplate)context.getBean("redisTemplate");
    System.out.println(demoBean);
 }

参考链接:https://blog.csdn.net/qq924862077/article/details/81583739 


相关文章
|
22天前
|
缓存 Java 开发者
【Spring】原理:Bean的作用域与生命周期
本文将围绕 Spring Bean 的作用域与生命周期展开深度剖析,系统梳理作用域的类型与应用场景、生命周期的关键阶段与扩展点,并结合实际案例揭示其底层实现原理,为开发者提供从理论到实践的完整指导。
|
20天前
|
人工智能 Java 开发者
【Spring】原理解析:Spring Boot 自动配置
Spring Boot通过“约定优于配置”的设计理念,自动检测项目依赖并根据这些依赖自动装配相应的Bean,从而解放开发者从繁琐的配置工作中解脱出来,专注于业务逻辑实现。
|
1月前
|
Java 关系型数据库 数据库
深度剖析【Spring】事务:万字详解,彻底掌握传播机制与事务原理
在Java开发中,Spring框架通过事务管理机制,帮我们轻松实现了这种“承诺”。它不仅封装了底层复杂的事务控制逻辑(比如手动开启、提交、回滚事务),还提供了灵活的配置方式,让开发者能专注于业务逻辑,而不用纠结于事务细节。
|
5月前
|
存储 人工智能 自然语言处理
RAG 调优指南:Spring AI Alibaba 模块化 RAG 原理与使用
通过遵循以上最佳实践,可以构建一个高效、可靠的 RAG 系统,为用户提供准确和专业的回答。这些实践涵盖了从文档处理到系统配置的各个方面,能够帮助开发者构建更好的 RAG 应用。
2744 114
|
2月前
|
缓存 安全 Java
Spring 框架核心原理与实践解析
本文详解 Spring 框架核心知识,包括 IOC(容器管理对象)与 DI(容器注入依赖),以及通过注解(如 @Service、@Autowired)声明 Bean 和注入依赖的方式。阐述了 Bean 的线程安全(默认单例可能有安全问题,需业务避免共享状态或设为 prototype)、作用域(@Scope 注解,常用 singleton、prototype 等)及完整生命周期(实例化、依赖注入、初始化、销毁等步骤)。 解析了循环依赖的解决机制(三级缓存)、AOP 的概念(公共逻辑抽为切面)、底层动态代理(JDK 与 Cglib 的区别)及项目应用(如日志记录)。介绍了事务的实现(基于 AOP
116 0
|
2月前
|
监控 架构师 NoSQL
spring 状态机 的使用 + 原理 + 源码学习 (图解+秒懂+史上最全)
spring 状态机 的使用 + 原理 + 源码学习 (图解+秒懂+史上最全)
|
4月前
|
前端开发 Java 数据库连接
Spring核心原理剖析与解说
每个部分都是将一种巨大并且复杂的技术理念传达为更易于使用的接口,而这就是Spring的价值所在,它能让你专注于开发你的应用,而不必从头开始设计每一部分。
170 32
|
4月前
|
Java 开发者 Spring
Spring框架 - 深度揭秘Spring框架的基础架构与工作原理
所以,当你进入这个Spring的世界,看似一片混乱,但细看之下,你会发现这里有个牢固的结构支撑,一切皆有可能。不论你要建设的是一座宏大的城堡,还是个小巧的花园,只要你的工具箱里有Spring,你就能轻松搞定。
204 9
|
10月前
|
XML Java 开发者
Spring Boot开箱即用可插拔实现过程演练与原理剖析
【11月更文挑战第20天】Spring Boot是一个基于Spring框架的项目,其设计目的是简化Spring应用的初始搭建以及开发过程。Spring Boot通过提供约定优于配置的理念,减少了大量的XML配置和手动设置,使得开发者能够更专注于业务逻辑的实现。本文将深入探讨Spring Boot的背景历史、业务场景、功能点以及底层原理,并通过Java代码手写模拟Spring Boot的启动过程,为开发者提供一个全面的理解。
189 0