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

相关推荐