zoukankan      html  css  js  c++  java
  • Spring内嵌Tomcat的过滤器链的过滤原理

    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方法

  • 相关阅读:
    winform文本打印
    自动升级程序
    构造使用IN子句的动态TransactSQL方法进行编号查询
    加解密
    Caffe源码Layer类
    Caffe源码SyncedMemory类
    Caffe源码Blob类
    CSS 溢出文本显示省略号的方法(兼容 IE、FF、Chrome)
    文字内容超出自动换到第二行显示
    js面向对象编程两个主要点
  • 原文地址:https://www.cnblogs.com/wangxuejian/p/13662957.html
Copyright © 2011-2022 走看看