DelegatingFilterProxy类的一些内部运行机制,其实主要做用就是一个代理模式的应用,能够把servlet 容器中的filter同spring容器中的bean关联起来。楼主说这样能够可拔插的效果。是能够像处理bean同样销毁。
html
使用过springSecurity的朋友都知道,首先须要在web.xml进行如下配置java
<filter> <filter-name>springSecurityFilterChain</filter-name> <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class> <init-param> <param-name>targetFilterLifecycle</param-name> <param-value>true</param-value> <!-- 默认是false --> </init-param> </filter> <filter-mapping> <filter-name>springSecurityFilterChain</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
非springSecurity用法以下:web
<filter> <filter-name>DelegatingFilterProxy</filter-name> <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class> <init-param> <param-name>targetBeanName</param-name> <!-- 自定义filter --> <param-value>exportExamineFilter</param-value> </init-param> <init-param> <!-- 判断targetFilterLifecycle属性是false仍是true,决定是否调用自定义类的init()、destry()方法 --> <param-name>targetFilterLifecycle</param-name> <param-value>false</param-value> </init-param> </filter> <filter-mapping> <filter-name>DelegatingFilterProxy</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
从这个配置中,可能会给咱们形成一个错觉,觉得DelegatingFilterProxy类就是springSecurity的入口,但其实这个类位于spring-web-3.0.5.RELEASE.jar这个jar下面,说明这个类自己是和springSecurity无关。DelegatingFilterProxy类继承于抽象类GenericFilterBean,间接地implement 了javax.servlet.Filter接口,Servlet容器在启动时,首先会调用Filter的init方法,GenericFilterBean的做用主要是能够把Filter的初始化参数自动地set到继承于GenericFilterBean类的Filter中去。在其init方法的以下代码就是作了这个事:spring
PropertyValues pvs = new FilterConfigPropertyValues(filterConfig, this.requiredProperties); BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(this); ResourceLoader resourceLoader = new ServletContextResourceLoader(filterConfig.getServletContext()); bw.registerCustomEditor(Resource.class, new ResourceEditor(resourceLoader)); initBeanWrapper(bw); bw.setPropertyValues(pvs, true);
另外在init方法中调用了initFilterBean()方法,该方法是GenericFilterBean类是特意留给子类扩展用的安全
protected void initFilterBean() throws ServletException { // 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. synchronized (this.delegateMonitor) { WebApplicationContext wac = findWebApplicationContext(); if (wac != null) { this.delegate = initDelegate(wac); } } }
能够看出上述代码首先看Filter是否提供了targetBeanName初始化参数,若是没有提供则直接使用filter的name作为beanName,产生了beanName后,因为咱们在web.xml的filter的name是springSecurityFilterChain,从spring的IOC容器中取出bean的代码是initDelegate方法,下面是该方法代码:app
protected Filter initDelegate(WebApplicationContext wac) throws ServletException { Filter delegate = wac.getBean(getTargetBeanName(), Filter.class); if (isTargetFilterLifecycle()) { delegate.init(getFilterConfig()); } return delegate; }
经过跟踪代码,发现取出的bean是org.springframework.security.FilterChainProxy,该类也是继承于GenericFilterBean,取出bean后,判断targetFilterLifecycle属性是false仍是true,决定是否调用该类的init方法。这个FilterChainProxy bean实例最终被保存在DelegatingFilterProxy类的delegate属性里,
下面看一下DelegatingFilterProxy类的doFilter方法框架
public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws ServletException, IOException { // Lazily initialize the delegate if necessary. Filter delegateToUse = null; synchronized (this.delegateMonitor) { if (this.delegate == null) { WebApplicationContext wac = findWebApplicationContext(); if (wac == null) { throw new IllegalStateException("No WebApplicationContext found: no ContextLoaderListener registered?"); } this.delegate = initDelegate(wac); } delegateToUse = this.delegate; } // Let the delegate perform the actual doFilter operation. invokeDelegate(delegateToUse, request, response, filterChain); }
真正要关注invokeDelegate(delegateToUse, request, response, filterChain);这句代码,在下面能够看出DelegatingFilterProxy类实际是用其delegate属性即org.springframework.security.FilterChainProxy实例的doFilter方法来响应请求。ui
protected void invokeDelegate( Filter delegate, ServletRequest request, ServletResponse response, FilterChain filterChain) throws ServletException, IOException { delegate.doFilter(request, response, filterChain); }
以上就是DelegatingFilterProxy类的一些内部运行机制,其实主要做用就是一个代理模式的应用,能够把servlet 容器中的filter同spring容器中的bean关联起来。
此外还要注意一个DelegatingFilterProxy的一个初始化参数:targetFilterLifecycle ,其默认值为false 。 但若是被其代理的filter的init()方法和destry()方法须要被调用时,须要设置targetFilterLifecycle为true。具体可见DelegatingFilterProxy中的以下代码:this
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); } } } } protected Filter initDelegate(WebApplicationContext wac) throws ServletException { Filter delegate = wac.getBean(getTargetBeanName(), Filter.class); if (isTargetFilterLifecycle()) { //注意这行 delegate.init(getFilterConfig()); } return delegate; }
转载地址:http://www.cnblogs.com/hzhuxin/archive/2011/12/19/2293730.htmlurl
转载有用的评论以下:
https://blog.csdn.net/romantic_pk/article/details/53082201
这也是为何org.springframework.web.filter.DelegatingFilterProxy这个类是位于spring-web这个jar包下面。
我研究了一下,其过程是这样的。
web.xml下面我们会配一个listen-class为org.springframework.web.context.ContextLoaderListener,而后其对应的contextConfigLocation Spring会把spring context及spring security的XML配置文件装载入Spring Bean容器中(由XmlWebApplicationContent来装载),而后在兄台上面说的
Filter delegate = wac.getBean(getTargetBeanName(), Filter.class);
这个方法的时候,Delegate就会向Spring容器要实现了Filter的叫targetBeanName的值(你上面配的是springSecurityFilterChain)的类,若是咱们contextConfigLocation配置了Spring security的配置文件,天然就有这个springSecurityFilterChain的Bean了。若是咱们不想用Spring Security,那么也能够在此处替换成咱们要的security实现类。
不过我却是没有搞明白为何org.springframework.security.web.FilterChainProxy在Spring容器中的BeanName为何是叫springSecurityFilterChain?