shiro学习17-shiro提供的filter-AbstractShiroFilter
这个类是上面的OncePerRequestFilter的子类,实现了其doInternalFilter方法,所有的业务逻辑在里面实现。这个类也是一个抽象类,但是没有任何的抽象方法,所以只要集成他就可以直接使用了。
这是一个及其重要的类,shiro集成spring的ShiroFilterFactoryBean返回给spring context中的bean就是他,在ShiroFilterFactoryBean类中,getObject方法就是返回给spring context的bean,里面返回的就是AbstractShiroFilter类,具体的实现是org.apache.shiro.spring.web.ShiroFilterFactoryBean.SpringShiroFilter这个类,在构造方法中将SecurityManager和FilterChainResolver类传入到AbstractShiroFilter中。
private static final class SpringShiroFilter extends AbstractShiroFilter { protected SpringShiroFilter(WebSecurityManager webSecurityManager, FilterChainResolver resolver) { super(); if (webSecurityManager == null) { throw new IllegalArgumentException("WebSecurityManager property cannot be null."); } setSecurityManager(webSecurityManager); if (resolver != null) { setFilterChainResolver(resolver); } } }
在这个类中将filterChainResolver传入进去,filterChainResolver里面有一个属性FilterChainManager,这里面有一个属性filterChains就表示我们在shiroFilterFactoryBean中配置的所有的路径(也可以说是filter的名字)+filter,在filterChainResolver还有一个属性pathMatcher,用来将访问的url和我们匹配的filter的名字像匹配,决定都是调用哪些filter,也就是一个filterChain。
我们再来看一下AbstractShiroFilter中的 doFilterInternal方法
protected void doFilterInternal(ServletRequest servletRequest, ServletResponse servletResponse, final FilterChain chain) throws ServletException, IOException { Throwable t = null; try { final ServletRequest request = prepareServletRequest(servletRequest, servletResponse, chain); final ServletResponse response = prepareServletResponse(request, servletResponse, chain); final Subject subject = createSubject(request, response); //noinspection unchecked subject.execute(new Callable() { public Object call() throws Exception { updateSessionLastAccessTime(request, response); executeChain(request, response, chain);//最后调用的是这个方法, return null; } }); } catch (ExecutionException ex) { t = ex.getCause(); } catch (Throwable throwable) { t = throwable; } if (t != null) { if (t instanceof ServletException) { throw (ServletException) t; } if (t instanceof IOException) { throw (IOException) t; } //otherwise it's not one of the two exceptions expected by the filter method signature - wrap it in one: String msg = "Filtered request failed."; throw new ServletException(msg, t); } }
executeChain方法如下:
protected void executeChain(ServletRequest request, ServletResponse response, FilterChain origChain) throws IOException, ServletException { FilterChain chain = getExecutionChain(request, response, origChain);//调用这个方法获得此次访问应该调用的filter链。 chain.doFilter(request, response); }
getExecutionChain的代码如下:
protected FilterChain getExecutionChain(ServletRequest request, ServletResponse response, FilterChain origChain) { FilterChain chain = origChain; FilterChainResolver resolver = getFilterChainResolver();//他是根据配置的filterChainResolver来获得匹配的filterChain。这里的origChain就是我们在web.xml里面配置的那个DelegatingFilter,就是用来调用shiro的所有请求的代理filter,所有访问shiro的filter都是由它获得。 if (resolver == null) { log.debug("No FilterChainResolver configured. Returning original FilterChain."); return origChain; } FilterChain resolved = resolver.getChain(request, response, origChain); if (resolved != null) { log.trace("Resolved a configured FilterChain for the current request."); chain = resolved; } else { log.trace("No FilterChain configured for the current request. Using the default."); } return chain; }
通过这个方法我们基本就知道了shiro的处理请求的流程,当某个请求来了之后,他是通过调用配置的ChainResolver调用匹配的路径,如果找到了对应的路径就执行配置的路径后面的所有的filter。另外ShiroFilterFactoryBean向spring context中传入的bean不是传入的自身,而是传入的org.apache.shiro.spring.web.ShiroFilterFactoryBean.SpringShiroFilter这个类,传入的类(也就是spring中的ObjectType)是SpringShiroFilter.class;也不是他自身。