shiro学习18-shiro提供的filter类-AdviceFilter
这个类和之前的AbstractShiroFilter是平级的,都是OnecPerRequestFilter的子类,我们从他的名字Advice中就能联想到他的用意——AOP,在spring中有很多的advice,也就是通知,比如前置通知,后置通知,最终通知等,这个类允许通过很多方法实现filter中的aop的特点,比如preHandle(前置通知),postHandle(后置通知,但是在抛异常的情况下可能不执行,),afterCompletion(最终通知,一定会执行)。
先看看他的doFilterInternal方法:
public void doFilterInternal(ServletRequest request, ServletResponse response, FilterChain chain) throws ServletException, IOException { Exception exception = null; try { boolean continueChain = preHandle(request, response);//先调用preHandle,判断能否执行 if (log.isTraceEnabled()) { log.trace("Invoked preHandle method. Continuing chain?: [" + continueChain + "]"); } if (continueChain) {//如果preHandle返回true,则继续执行后面的filter和servlet。 executeChain(request, response, chain); } postHandle(request, response);//执行完成之后的操作。 if (log.isTraceEnabled()) { log.trace("Successfully invoked postHandle method"); } } catch (Exception e) { exception = e; } finally { cleanup(request, response, exception); } }
ExecuteChain的方法特别简单,就是执行剩余的chain。因为我们在配置一个路径的时候可能配置多个filter,并不是指配置一个filter。
protected void executeChain(ServletRequest request, ServletResponse response, FilterChain chain) throws Exception { chain.doFilter(request, response); }
如果preHandle返回的是false则表示不再执行直接调用postHandle,剩余的filter servlet也不再被调用,这样啥也没有返回给页面,页面显示的是一篇空白。在postHandle中没有任何的返回,表示单纯的操作。
最后在finally中调用的是cleanup方法,源码如下:
protected void cleanup(ServletRequest request, ServletResponse response, Exception existing) throws ServletException, IOException { Exception exception = existing; try { afterCompletion(request, response, exception);//实际调用的就是这个方法, if (log.isTraceEnabled()) { log.trace("Successfully invoked afterCompletion method."); } } catch (Exception e) { if (exception == null) { exception = e; } else { log.debug("afterCompletion implementation threw an exception. This will be ignored to " + "allow the original source exception to be propagated.", e); } } if (exception != null) { if (exception instanceof ServletException) { throw (ServletException) exception; } else if (exception instanceof IOException) { throw (IOException) exception; } else { if (log.isDebugEnabled()) { String msg = "Filter execution resulted in an unexpected Exception " + "(not IOException or ServletException as the Filter API recommends). " + "Wrapping in ServletException and propagating."; log.debug(msg); } throw new ServletException(exception); } } }
在这个方法中调用的是afterComletion,所以就相当于是在finally调用aftercompletion方法,所以如果我们有些操作必须要执行的话,必须在复写的afterCompetion方法中进行,因为这样的话一定会执行。
我们在看看这个类中的preHandle postHandle afterCompletion
protected boolean preHandle(ServletRequest request, ServletResponse response) throws Exception { return true; } @SuppressWarnings({"UnusedDeclaration"}) protected void postHandle(ServletRequest request, ServletResponse response) throws Exception {} @SuppressWarnings({"UnusedDeclaration"}) public void afterCompletion(ServletRequest request, ServletResponse response, Exception exception) throws Exception { }
这三个方法尽管不是抽象方法,但是几乎没有任何的操作,而且上面的javadoc也说明这些方法需要我们根据具体的业务逻辑进行覆写。所以我们可以根据业务逻辑进行类似aop的操作了。当然如果我们的业务逻辑没有需要用到这些的话,保持默认就可以了。
Advice有两个子类,一个是LogoutFilter,一个是PathMatchingFilter。