继承Shiro和Spring时,我们都知道要先通过web.xml部署描述符或者其他方式,向ServletContext添加过滤器。因为要与Spring继承,所以添加的过滤器其实是spring相关的,也就是DelegatingFilterProxy。
DelegatingFilterProxy的所有任务交给Root ApplicationContext这个级别的Spring容器中的一个bean来完成。如果在配置DelegatingFilterProxy过滤器的时候没有指定targetName属性,那么DelegatingFilterProxy会去到Spring容器里找id为<filter-name>的bean,所以我们要在Spring容器里配置这样一个Bean。从这里开始与Shiro就有关系了。
尽管已经知道了id应当是什么,但是还不清除这个Bean的类型,它是ShiroFilterFactoryBean。先不理会什么是FactoryBean,先看它有哪些属性,这关系到可以怎样配置它。
如果你已经在web.xml中配置过ShiroFilterFactoryBean,那么你会对其中的属性非常熟悉。它们是如何起作用的呢。这里就必须清除FactoryBean是什么了。
这是ShiroFilterFactoryBean的类图。以上两个接口都是Spring相关的。这里涉及到Spring中Bean的声明周期,那是另外一个问题了。总之,当请求一个FactoryBean时,得到不是这个类本身的实例,而是它的getObject()方法返回的对象。那ShiroFilterFactoryBean的getObject方法是什么呢?它和另一个creatInstance方法直接相关:
直接看最后一行,最终的Bean类型是SpringShiroFilter。它得到两个参数,第一个参数securityManager正是我们在配置ShiroFilterFactoryBean中指定的,第二个参数的得来非常复杂,现在只需在整体上知道chainResolver能将请求路径匹配到恰当的过滤器链。
此次,在web.xml中在DelegatingFilterProxy上设置的过滤路径,过滤任务交给了<filter-name>指出的bean,这个bean看上去是ShiroFilterFactoryBean,实际上却是SpringShiroFilter。下面开始真正的SpringShiroFilter之旅。
从AbstractFilter开始,在其init(FilterConfig filterConfig)方法中,完成了持有ServletContext的任务。这个方法会在生成过滤器实例时由Servlet容器自动调用。
从NameableFilter开始,可以在运行过程中重新设置Filter的name属性。然后是OncePerRequestFilter。
注意,到现在为止我们仍然是在谈论一个过滤器,它的类型是SpringShiroFilter,它在Init方法持有了ServletContext。当恰当的路径被请求时,它的doFilter方法被Servlet容器调用。alreadyFilteredAttributeName其实就是Filter的name属性。显然首次调用时,执行的是第二条黑线所示的方法,这个方法被它的子类AbstractShiroFilter实现。
SpringShiroFilter过滤器执行到这一步开始包装请求,响应,创建Subject了。因为创建Subject和包装后的request与response相关,所以先探索如何包装的request和response。请看起底Shiro(2)