本来是打算写shiro的过滤链是如何处理的,但是它是通过Spring的DelegatingFilterProxy来实现的,所以先得把DelegatingFilterProxy讲清楚。
顾名思义,DelegatingFilterProxy是一个代理类,代理我们标准的Filter类,并将其委托给一个实现了Filter接口的实例,不同之处在于这个实例是托管到spring中的。好处就很明显了,它可以享受到spring的便利之处,例如在filter类中注入其他的spring bean,更为复杂的初始化逻辑等等。
既然是托管到了spring中,那么filter的生命周期就交给了spring来管理。但是filter是有自己的生命周期的,DelegatingFilterProxy通过一个名叫targetFilterLifecycle的属性指定是否需要完成filter自己的生命周期方法。
讲了这么多,先看看DelegatingFilterProxy的庐山真面目:
public class DelegatingFilterProxy extends GenericFilterBean {
private String contextAttribute;
private WebApplicationContext webApplicationContext;
private String targetBeanName;
private boolean targetFilterLifecycle = false;
private volatile Filter delegate;
private final Object delegateMonitor = new Object();
// 省略了方法
}
属性最重要的就是代理的Filter了,所有的过滤操作都由delegate来实现。webApplicationContext是spring mvc的上下文,delegate需要通过webApplicationContext来获取。targetFilterLifecycle是指明是否需要调用Filter自有的生命周期方法,默认是false。
大家可以看到DelegatingFilterProxy继承了GenericFilterBean,对于GenericFilterBean,大家只需知道他实现了Filter接口就行了。
接下来再看看DelegatingFilterProxy有哪些重要的方法:
@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) {
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) {
this.delegate = initDelegate(wac);
}
}
}
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
// Lazily initialize the delegate if necessary.
Filter delegateToUse = this.delegate;
if (delegateToUse == null) {
synchronized (this.delegateMonitor) {
if (this.delegate == null) {
WebApplicationContext wac = findWebApplicationContext();
if (wac == null) {
throw new IllegalStateException("No WebApplicationContext found: " +
"no ContextLoaderListener or DispatcherServlet registered?");
}
this.delegate = initDelegate(wac);
}
delegateToUse = this.delegate;
}
}
// Let the delegate perform the actual doFilter operation.
invokeDelegate(delegateToUse, request, response, filterChain);
}
首先是初始化代理的filterBean,如果定义filter的时候给出了targetBeanName,那么则通过webAppliction获取对应的bean,否则根据filterName去获取对应的bean。该方法会在filter的init方法调用时被调用,调用时机在GenericFilterBean里面。在doFilter的时候,则通过调用delegate的doFilter来实现,也就是上面的invokeDelegate()方法。
protected void invokeDelegate(
Filter delegate, ServletRequest request, ServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
delegate.doFilter(request, response, filterChain);
}
到这里就是很熟悉的Filter调用模式了。
之前说过,通过代理filter,delegate的生命周期就交给了spring来管理。但是filter是有自己的生命周期的,DelegatingFilterProxy通过一个名叫targetFilterLifecycle的属性指定是否需要完成filter自己的生命周期方法。在bean的创建和销毁时,判断是否需要调用filter的对应的方法。
@Override
public void destroy() {
Filter delegateToUse = this.delegate;
if (delegateToUse != null) {
destroyDelegate(delegateToUse);
}
}
附:代码示例