Spring:代理Filter:DelegatingFilterProxy原理和作用
转自:https://blog.csdn.net/fly910905/article/details/95062258
DelegatingFilterProxy就是一个对于servlet filter的代理,用这个类的好处主要是通过Spring容器来管理servlet filter的生命周期,
- 还有就是如果filter中需要一些Spring容器的实例,可以通过spring直接注入,
- 另外读取一些配置文件这些便利的操作都可以通过Spring来配置实现。
Spring web在设计的时候考虑到某些功能的实现是
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
1 @Override 2 protected void initFilterBean() throws ServletException { 3 synchronized (this.delegateMonitor) { 4 if (this.delegate == null) { 5 // If no target bean name specified, use filter name. 6 //当Filter配置时如果没有设置targentBeanName属性,则直接根据Filter名称来查找 7 if (this.targetBeanName == null) { 8 this.targetBeanName = getFilterName(); 9 } 10 // Fetch Spring root application context and initialize the delegate early, 11 // if possible. If the root application context will be started after this 12 // filter proxy, we'll have to resort to lazy initialization. 13 WebApplicationContext wac = findWebApplicationContext(); 14 if (wac != null) { 15 //从Spring容器中获取注入的Filter的实现类 16 this.delegate = initDelegate(wac); 17 } 18 } 19 } 20 } 21 22 protected Filter initDelegate(WebApplicationContext wac) throws ServletException { 23 //从Spring 容器中获取注入的Filter的实现类 24 Filter delegate = wac.getBean(getTargetBeanName(), Filter.class); 25 if (isTargetFilterLifecycle()) { 26 delegate.init(getFilterConfig()); 27 } 28 return delegate; 29 }
2、在DelegatingFilterProxy的实现方法doFilter中,其实最终调用的是委派的类delegate
1 @Override 2 protected void initFilterBean() throws ServletException { 3 synchronized (this.delegateMonitor) { 4 if (this.delegate == null) { 5 // If no target bean name specified, use filter name. 6 //当Filter配置时如果没有设置targentBeanName属性,则直接根据Filter名称来查找 7 if (this.targetBeanName == null) { 8 this.targetBeanName = getFilterName(); 9 } 10 // Fetch Spring root application context and initialize the delegate early, 11 // if possible. If the root application context will be started after this 12 // filter proxy, we'll have to resort to lazy initialization. 13 WebApplicationContext wac = findWebApplicationContext(); 14 if (wac != null) { 15 //从Spring容器中获取注入的Filter的实现类 16 this.delegate = initDelegate(wac); 17 } 18 } 19 } 20 } 21 22 protected Filter initDelegate(WebApplicationContext wac) throws ServletException { 23 //从Spring 容器中获取注入的Filter的实现类 24 Filter delegate = wac.getBean(getTargetBeanName(), Filter.class); 25 if (isTargetFilterLifecycle()) { 26 delegate.init(getFilterConfig()); 27 } 28 return delegate; 29 }
总结:Spring web通过提高DelegatingProxyFilter类给开发者提供了便利
DelegatingFilterProxy运用
需求
在springboot中 使用了filter, 并且注入了业务工具类(APIUtil ),但注入是null
在springboot中 使用了filter, 并且注入了业务工具类(APIUtil ),但注入是null
其实Spring中,web应用启动的顺序是:listener->filter->servlet,先初始化listener,然后再来就filter的初始化,再接着才到我们的dispathServlet的初始化
解决办法1:
1 public class TokenAuthFilter implements Filter { 2 3 private final static Logger log = LoggerFactory.getLogger(TokenAuthFilter.class); 4 5 @Autowired 6 private APIUtil apiUtil; 7 }
新增一个config类,用来手工创建filter的bean, 例如:
1 @Configuration 2 public class WebConfig { 3 4 @Bean 5 public Filter tokenAuthFilter() { 6 7 return new TokenAuthFilter(); 8 } 9 /** 10 * 注册filter,统一处理api开头的请求 11 * @return FilterRegistrationBean 12 */ 13 @Bean 14 public FilterRegistrationBean tokenAuthFilterRegistration() { 15 FilterRegistrationBean registration = new FilterRegistrationBean(); 16 // DelegatingFilterProxy把servlet 容器中的filter同spring容器中的bean关联起来 17 registration.setFilter(new DelegatingFilterProxy("tokenAuthFilter")); 18 registration.addUrlPatterns("/api/*"); 19 registration.setName("tokenAuthFilter"); 20 registration.setOrder(1); 21 return registration; 22 } 23 24 }
解决办法2:
过滤器是servlet规范中定义的,并不归spring容器管理,也无法直接注入spring中的bean(会报错)
初始化时通过spring上下文获取,进行bean的初始化:
1 @Override 2 public void init(FilterConfig filterConfig) throws ServletException { 3 ApplicationContext context = WebApplicationContextUtils.getWebApplicationContext(filterConfig.getServletContext()); 4 RedisTemplate demoBean = (RedisTemplate)context.getBean("redisTemplate"); 5 System.out.println(demoBean); 6 }
相关文章
- Spring + JdbcTemplate + JdbcDaoSupport
- Spring 框架基础(01):核心组件总结,基础环境搭建
- 阿里内部最新教材:Spring+SpringBoot+SpringCloud 全家桶第五版
- MAVEN_SPRING+SPRINGMVC+MYBATIS+FREEMARKER 整合
- spring batch(二):核心部分(1):配置Spring batch
- Spring Boot2.2.X中Tomcat配置 错误定制
- 注意:Spring Boot 2.7开始spring.factories不推荐使用了,接下来这么玩...
- Spring Cloud Alibaba基础教程:Nacos配置的多文件加载与共享配置
- Spring集成Redis集群(含spring集成redis代码)
- spring的context---ServletContext WebApplicationContext---Spring各种上下文的关系详解
- spring mvc -- HttpMessageConverter、DispatcherServlet、Validator---@RequestBody @respondBody
- spring框架漏洞整理(Spring Boot Actuator命令执行漏洞)
- 【Spring常见错误】Initialization failed for ‘https://start.spring.io‘
- Spring Boot—19Session
- Spring Boot—19Cache
- springMVC和spring各自扫描自己的注解不要相互混淆
- spring mvc 中文参数乱码
- 【spring框架】AspectJ动态代理实现AOP
- spring源码分析之@Conditional
- Spring 的优秀工具类盘点---转
- 曹工说Spring Boot源码(13)-- AspectJ的运行时织入(Load-Time-Weaving),基本内容是讲清楚了(附源码)
- 曹工说Spring Boot源码(12)-- Spring解析xml文件,到底从中得到了什么(context:component-scan完整解析)