https://www.cnblogs.com/zhanhaitao/p/7857245.html
初心
DelegatingFilterProxy
これは、サーブレットフィルタのためのプロキシです
- このクラスを使用する利点は、サーブレットフィルタのライフサイクルを管理するために、Springコンテナを通じて主です
- いくつかの例は、直接注射ばねにより、スプリングは、所望のフィルター容器内に存在する場合
- また、いくつかの設定ファイルは、これらの操作が実装春によって構成することができやすく読み
DelegatingFilterProxy
存在spring-web
役割があるパッケージ、filter的代理
間接的Filterインタフェースを実装し、実際には、エージェントのフィルター実装クラスのデリゲートにSpringコンテナから取り出したのdoFilterに呼び出されます。
私たちはそこでは、チャート上で見ることができるDelegatingFilterProxy
クラスの継承GenericFilterBean
、間接的にこのインタフェースフィルタを実装するため、クラスフィルタに属します。
その後、彼らは、フィルタのinit、のdoFilterを実現しているだろう、3つのメソッドを破壊します。
演技の実現
# 初期化
まず、我々は見てinit
私たちが知っている、方法フィルタは、初期化メソッドのinitを実行する場合
ソースから、我々は方法がGenericFilterBeanクラスに実装され、特定のコードを見つけることができ、具体的な機能は以下のとおりです。
- 春ベースのフォームなどの特定のクラス、維持しやすい春
- そして主な目的は、次のコードで具現見るために、春に維持ターゲットフィルタを見つけることで達成(DelegatingFilterProxy用)サブクラスでinitFilterBeanメソッドを呼び出します。
/**
* Standard way of initializing this filter.
* Map config parameters onto bean properties of this filter, and
* invoke subclass initialization.
* @param filterConfig the configuration for this filter
* @throws ServletException if bean properties are invalid (or required
* properties are missing), or if subclass initialization fails.
* @see #initFilterBean
*/
@Override
public final void init(FilterConfig filterConfig) throws ServletException {
Assert.notNull(filterConfig, "FilterConfig must not be null");
this.filterConfig = filterConfig;
!将该类封装成spring特有的bean形式,方便spring维护
↓
// Set bean properties from init parameters.
PropertyValues pvs = new FilterConfigPropertyValues(filterConfig, this.requiredProperties);
if (!pvs.isEmpty()) {
try {
BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(this);
ResourceLoader resourceLoader = new ServletContextResourceLoader(filterConfig.getServletContext());
Environment env = this.environment;
if (env == null) {
env = new StandardServletEnvironment();
}
bw.registerCustomEditor(Resource.class, new ResourceEditor(resourceLoader, env));
initBeanWrapper(bw);
bw.setPropertyValues(pvs, true);
}
catch (BeansException ex) {
String msg = "Failed to set bean properties on filter '" +
filterConfig.getFilterName() + "': " + ex.getMessage();
logger.error(msg, ex);
throw new NestedServletException(msg, ex);
}
}
!该方法 initFilterBean 在子类 (DelegatingFilterProxy) 中实现
我们可以到DelegatingFilterPoxy中去看看,具体完成了那些工作?
1、找到要代理bean的id ==> targetBeanName
2、在spring,bean容器中找到具体被代理的filter ==> delegate
↓
// Let subclasses do whatever initialization they like.
initFilterBean();
if (logger.isDebugEnabled()) {
logger.debug("Filter '" + filterConfig.getFilterName() + "' configured for use");
}
}
initFilterBean()
この方法の実行2つの主な機能:(以下のコード)
- プロキシクラスは、春に設定されている検索
id
とに割り当てられましたtargetBeanName
。 - 使用が見つかりました
id
からspring
見つかったコンテナの特定のプロキシクラス、およびに割り当てられましたdelegate
@Override
protected void initFilterBean() throws ServletException {
synchronized (this.delegateMonitor) {
if (this.delegate == null) {
// If no target bean name specified, use filter name.
if (this.targetBeanName == null) {
!找到要被代理的filter在spring中配置的id(name)
↓
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) {
!找到具体被代理的filter
↓
this.delegate = initDelegate(wac);
}
}
}
}
getFilterName()
この方法の効果は、エージェントによって取得されたfilter
スプリングに配置id
(以下)
/**
* Make the name of this filter available to subclasses.
* Analogous to GenericServlet's {@code getServletName()}.
* <p>Takes the FilterConfig's filter name by default.
* If initialized as bean in a Spring application context,
* it falls back to the bean name as defined in the bean factory.
* @return the filter name, or {@code null} if none available
* @see javax.servlet.GenericServlet#getServletName()
* @see javax.servlet.FilterConfig#getFilterName()
* @see #setBeanName
*/
@Nullable
protected String getFilterName() {
!找到被代理filter在spring中配置的id
↓
return (this.filterConfig != null ? this.filterConfig.getFilterName() : this.beanName);
}
initDelegate()
この方法の効果は、特定のバネを容器から取得し、プロキシ filter
/**
* Initialize the Filter delegate, defined as bean the given Spring
* application context.
* <p>The default implementation fetches the bean from the application context
* and calls the standard {@code Filter.init} method on it, passing
* in the FilterConfig of this Filter proxy.
* @param wac the root application context
* @return the initialized delegate Filter
* @throws ServletException if thrown by the Filter
* @see #getTargetBeanName()
* @see #isTargetFilterLifecycle()
* @see #getFilterConfig()
* @see javax.servlet.Filter#init(javax.servlet.FilterConfig)
*/
protected Filter initDelegate(WebApplicationContext wac) throws ServletException {
! 取出上面找到的 id
↓
String targetBeanName = getTargetBeanName();
Assert.state(targetBeanName != null, "No target bean name set");
! 找到被代理的filter
↓
Filter delegate = wac.getBean(targetBeanName, Filter.class);
if (isTargetFilterLifecycle()) {
delegate.init(getFilterConfig());
}
return delegate;
}
ここでは見ることができ、我々は、エージェントが欲しいfilter
実際に我々が設定されたタグのをfilter
filter-name
filterName
<filter-name>filterName</filter-name>
#のdoFilter
我々は見てとるdoFilter
主に使用して、特定の実装方法を、被代理的filter
と呼んinvokeDelegate
方法、
実装被代理filter
のdoFilter
方法、具体的な実装を、下のソースコードを参照してください。
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
! 得到被代理的filter
↓
// Lazily initialize the delegate if necessary.
Filter delegateToUse = this.delegate;
if (delegateToUse == null) {
synchronized (this.delegateMonitor) {
delegateToUse = this.delegate;
if (delegateToUse == null) {
WebApplicationContext wac = findWebApplicationContext();
if (wac == null) {
throw new IllegalStateException("No WebApplicationContext found: " +
"no ContextLoaderListener or DispatcherServlet registered?");
}
delegateToUse = initDelegate(wac);
}
this.delegate = delegateToUse;
}
}
! 执行被代理filter的doFilter方法
↓
// Let the delegate perform the actual doFilter operation.
invokeDelegate(delegateToUse, request, response, filterChain);
}
invokeDelegate
この方法は、のdoFilterのプロキシ・フィルタ方式であるの役割を実行することです
/**
* Actually invoke the delegate Filter with the given request and response.
* @param delegate the delegate Filter
* @param request the current HTTP request
* @param response the current HTTP response
* @param filterChain the current FilterChain
* @throws ServletException if thrown by the Filter
* @throws IOException if thrown by the Filter
*/
protected void invokeDelegate(
Filter delegate, ServletRequest request, ServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
delegate.doFilter(request, response, filterChain);
}
ここを参照してください、私はそれが今どのように我々はすべてのDelegatingFilterPoxyを理解すると信じています。
ここでは、春の+の士郎を見て、このクラスを使用する方法です
使用(SpringBoot環境)
需要
フィルタにspringbootで、注入さビジネスツール(APIUtil)が、注入がヌルであります
疑問が生じたので:springbootの注入Beanが使用されるフィルタは、ヌルソリューションです
分析:春は実際には、Webアプリケーションの順序が起動されます。
リスナー⇒フィルタ⇒サーブレット
それだけで私たちのdispathServletの初期化に続いた後、フィルタの初期化に戻ってくるし、その後、第1の初期化のリスナーであり、
理由
しかし サーブレットフィルタは、バネコンテナ管理を返さない、本明細書で定義され、直接スプリングビーンに注入することができない(与えられます)
溶液#1
public class TokenAuthFilter implements Filter {
private final static Logger log = LoggerFactory.getLogger(TokenAuthFilter.class);
@Autowired
private APIUtil apiUtil;
}
例えば、手で豆用のフィルタを作成し、Configクラスを追加します。
@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(高結合)
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);
}