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。