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