一马平川1

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::
public interface Filter {
public void init(FilterConfig filterConfig) throws ServletException;
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain);
public void destroy();
}
Filter是个独立的接口,其中只有3个方法,初始化,过滤和销毁.
其中init方法是用来初始化过滤器的, 而入参FilterConfig就是初始化过滤器的参数

destroy方法是一个钩子方法,用于在销毁过滤器时调用,以实现某些清理行为,比如释放内存,句柄,关闭线程.

doFilter才是要重点关注的方法,即: 干活的方法
该方法同时接收请求对象和响应对象,说明该过滤器在设计时,既可以在服务器处理前加工请求,也可以在处理后加工响应,而事实也确实如此.
此外还接收一个过滤器链,通过对比当前过滤器的编号和过滤器链上过滤器的总数,可以判断是否要继续向下传递过滤权.
例如:
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
  // 执行当前过滤器的主要逻辑:
if (ignore || (request.getCharacterEncoding() == null)) {
String characterEncoding = selectEncoding(request);
if (characterEncoding != null) {
request.setCharacterEncoding(characterEncoding);
}
}

// 将过滤的接力棒传给过滤器链
chain.doFilter(request, response);
}

过滤器链的doFilter:
@Override
public void doFilter(ServletRequest request, ServletResponse response)
throws IOException, ServletException {
  // 判断是否有安全检查,如果有,就判断是否有执行internalDoFilter的权限,如果没有就抛异常
if( Globals.IS_SECURITY_ENABLED ) {
final ServletRequest req = request;
final ServletResponse res = response;
try {
java.security.AccessController.doPrivileged(
new java.security.PrivilegedExceptionAction<Void>() {
@Override
public Void run()
throws ServletException, IOException {
internalDoFilter(req,res);
return null;
}
}
);
} catch( PrivilegedActionException pe) {
Exception e = pe.getException();
if (e instanceof ServletException)
throw (ServletException) e;
else if (e instanceof IOException)
throw (IOException) e;
else if (e instanceof RuntimeException)
throw (RuntimeException) e;
else
throw new ServletException(e.getMessage(), e);
}
  // 如果没有安全检查,就直接执行internalDoFilter方法
} else {
internalDoFilter(request,response);
}
}
internalDoFilter又是如何执行?
首先判断当前过滤器是不是最后一个过滤器,如果不是就继续执行下一个过滤器的过滤操作, 如果是,就执行当前请求的servlet.service()方法.
private void internalDoFilter(ServletRequest request, ServletResponse response) throws IOException, ServletException {

// 判断当前过滤器的编号是不是最后一个了,如果是,就从过滤器列表中获取下一个过滤器,然后判断是否有安全检查,如果没有,就执行下一个过滤器的doFilter过滤逻辑
if (pos < n) {
ApplicationFilterConfig filterConfig = filters[pos++];
try {
Filter filter = filterConfig.getFilter();
if (request.isAsyncSupported() && "false".equalsIgnoreCase( ilterConfig.getFilterDef().getAsyncSupported())) {
request.setAttribute(Globals.ASYNC_SUPPORTED_ATTR, Boolean.FALSE);
}
if( Globals.IS_SECURITY_ENABLED ) {
final ServletRequest req = request;
final ServletResponse res = response;
Principal principal = ((HttpServletRequest) req).getUserPrincipal();
Object[] args = new Object[]{req, res, this};
SecurityUtil.doAsPrivilege ("doFilter", filter, classType, args, principal);
} else {
filter.doFilter(request, response, this);
}
} catch (IOException | ServletException | RuntimeException e) {
throw e;
} catch (Throwable e) {
e = ExceptionUtils.unwrapInvocationTargetException(e);
ExceptionUtils.handleThrowable(e);
throw new ServletException(sm.getString("filterChain.filter"), e);
}
return;
}

  // 如果是最后一个过滤器,就执行service方法
// We fell off the end of the chain -- call the servlet instance
try {
if (ApplicationDispatcher.WRAP_SAME_OBJECT) {
lastServicedRequest.set(request);
lastServicedResponse.set(response);
}

if (request.isAsyncSupported() && !servletSupportsAsync) {
request.setAttribute(Globals.ASYNC_SUPPORTED_ATTR,
Boolean.FALSE);
}
// Use potentially wrapped request from this point
if ((request instanceof HttpServletRequest) && (response instanceof HttpServletResponse) && Globals.IS_SECURITY_ENABLED ) {
final ServletRequest req = request;
final ServletResponse res = response;
Principal principal = ((HttpServletRequest) req).getUserPrincipal();
Object[] args = new Object[]{req, res};
SecurityUtil.doAsPrivilege("service", servlet, classTypeUsedInService, args, principal);
} else {
servlet.service(request, response);
}
} catch (IOException | ServletException | RuntimeException e) {
throw e;
} catch (Throwable e) {
e = ExceptionUtils.unwrapInvocationTargetException(e);
ExceptionUtils.handleThrowable(e);
throw new ServletException(sm.getString("filterChain.servlet"), e);
} finally {
if (ApplicationDispatcher.WRAP_SAME_OBJECT) {
lastServicedRequest.set(null);
lastServicedResponse.set(null);
}
}
}
总结:
1. N个过滤器的按顺序执行是通过过滤器链对象的操作实现,通过判断当前过滤器的编号来判断过滤器是否全部执行完毕.
2. 如果没有执行完毕,就执行下一个,否则就执行servlet的service方法

posted on 2020-09-13 20:20  一马平川1  阅读(492)  评论(0编辑  收藏  举报