TomCat之Filter小析

来源:互联网 发布:淘宝衣服一元包邮 编辑:程序博客网 时间:2024/06/09 08:18

对于做过web开发的人来说,Servlet中的过滤器肯定都不会陌生。这里我尝试着分析一下TomCat服务器中对于Filter是怎么组装的。在这之前,先把主要的几个类列一下:

  1. Filter 过滤器接口
  2. FilterChain 过滤器链
  3. FilterConfig 过滤器的配置
  4. FilterDef 过滤器的配置和描述
  5. ApplicationFilterChain 调用过滤器链
  6. ApplicationFilterConfig 获取过滤器
  7. ApplicationFilterFactory 组装过滤器链

上面的这几个类是组装过滤器中比较核心的一些类。OK下面再说几个比较重要的类:

  1. WebXml 从名字我们可以就看出来这个一个存放web.xml中内容的类
  2. ContextConfig  一个web应用的上下文配置类
  3. StandardContext  一个web应用上下文(Context接口)的标准实现  
  4. StandardWrapperValve   一个标准Wrapper的实现。一个上下文一般包括一个或者多个包装器,每一个包装器表示一个servlet。
在ContextConfig中会创建WebXml的实例,解析Web.xml等等一系列的工作。当然也包括实例化过滤器的动作。我们先跳过这一部分,进入到StandardWrapperValve中,因为在这个类中会进行过滤器的组装的操作,Servlet的调用。
        ApplicationFilterChain filterChain =                ApplicationFilterFactory.createFilterChain(request, wrapper, servlet);
上面那句话的作用是创建一个应用过滤器链,我们进入到这个方法中看一下(在ApplicationFilterFactory这个类中):
        StandardContext context = (StandardContext) wrapper.getParent();//这个Context代表的是一个应用上下文的标准实现        FilterMap filterMaps[] = context.findFilterMaps();//获取FilterMaps 这个是在ContextConfig中组装的。内容是在web.xml中配置的filter        // If there are no filter mappings, we are done        if ((filterMaps == null) || (filterMaps.length == 0)) //如果web.xml中没有配置过滤器,则直接返回            return (filterChain);        // Acquire the information we will need to match filter mappings        String servletName = wrapper.getName();//获取Servlet的名字  一个StandardWrapperValue代表一个具体的Servlet        // Add the relevant path-mapped filters to this filter chain        for (int i = 0; i < filterMaps.length; i++) {  //这里开始循环filterMaps中配置的过滤器(Servlet3.0支持注解的方式添加过滤器,这里也会包含这一部分)            if (!matchDispatcher(filterMaps[i] ,dispatcher)) { //这里是过滤器支持的类型,包括 FORWARD、INCLUDE、REQUEST、ASYNC、ERROR                continue;            }            if (!matchFiltersURL(filterMaps[i], requestPath)) //这里判断是否和请求路径相匹配                continue;            ApplicationFilterConfig filterConfig = (ApplicationFilterConfig)                context.findFilterConfig(filterMaps[i].getFilterName()); //从应用上下文中查找对应的过滤器            if (filterConfig == null) {                // FIXME - log configuration problem                continue;            }            boolean isCometFilter = false;            if (comet) {                try {                    isCometFilter = filterConfig.getFilter() instanceof CometFilter;                } catch (Exception e) {                    // Note: The try catch is there because getFilter has a lot of                    // declared exceptions. However, the filter is allocated much                    // earlier                    Throwable t = ExceptionUtils.unwrapInvocationTargetException(e);                    ExceptionUtils.handleThrowable(t);                }                if (isCometFilter) {                    filterChain.addFilter(filterConfig); //添加过滤器到过滤器链中                }            } else {                filterChain.addFilter(filterConfig); //添加过滤器到过滤器链中            }        }
在下面还有一段和这一段类似的组装过滤器的内容,我们不再分析。我们看看addFilter这个方法中做了什么:
    void addFilter(ApplicationFilterConfig filterConfig) {        // Prevent the same filter being added multiple times        for(ApplicationFilterConfig filter:filters)             if(filter==filterConfig)//去掉重复的过滤器配置 这里用的是 ==                 return;        if (n == filters.length) {//对过滤器配置数组扩容 一次括十个长度            ApplicationFilterConfig[] newFilters =                new ApplicationFilterConfig[n + INCREMENT];            System.arraycopy(filters, 0, newFilters, 0, n);            filters = newFilters;        }        filters[n++] = filterConfig; //加入到数组中    }
下面我们再回到org.apache.catalina.core.StandardWrapperValve这个类的invoke方法中:
        // Call the filter chain for this request 注释写的很清楚 调用过滤器链        // NOTE: This also calls the servlet's service() method //同时也会调用servlet的service方法        try {            if ((servlet != null) && (filterChain != null)) { //如果存在过滤器链                // Swallow output if needed                if (context.getSwallowOutput()) { //需要吞咽输出 (不知道是什么东西)                    try {                        SystemLogHandler.startCapture();                        if (request.isAsyncDispatching()) { // Servlet3.0的新特性                            ((AsyncContextImpl)request.getAsyncContext()).doInternalDispatch();                        } else if (comet) { //这里不太清楚                             filterChain.doFilterEvent(request.getEvent());                        } else { //执行过滤器                            filterChain.doFilter(request.getRequest(),                                    response.getResponse());                        }                    } finally {                        String log = SystemLogHandler.stopCapture();                        if (log != null && log.length() > 0) {                            context.getLogger().info(log);                        }                    }                } else {                    if (request.isAsyncDispatching()) {                        ((AsyncContextImpl)request.getAsyncContext()).doInternalDispatch();                    } else if (comet) {                        filterChain.doFilterEvent(request.getEvent());                    } else { //执行过滤器                        filterChain.doFilter                            (request.getRequest(), response.getResponse());                    }                }
下面我们进入到org.apache.catalina.core.ApplicationFilterChain的doFilter方法中这个方法其实是调用的internalDoFilter(request,response);这个方法,我们直接进入到这个方法中:
    private void internalDoFilter(ServletRequest request,                                  ServletResponse response)        throws IOException, ServletException {        // Call the next filter if there is one        if (pos < n) { // n代表的是过滤器链中有多少个过滤器 pos代表当前执行到哪个过滤器了            ApplicationFilterConfig filterConfig = filters[pos++]; //获取要执行的过滤器配置             Filter filter = null;            try {                filter = filterConfig.getFilter(); //要执行的过滤器                support.fireInstanceEvent(InstanceEvent.BEFORE_FILTER_EVENT,                                          filter, request, response); //过滤器执行前的事件                if (request.isAsyncSupported() && "false".equalsIgnoreCase(                        filterConfig.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);//执行过滤器 这里可以看到最后传的参数是this 以达到循环调用的目的                }                support.fireInstanceEvent(InstanceEvent.AFTER_FILTER_EVENT,                                          filter, request, response); //过滤器执行后的事件
我们继续往下看
            return; //结束每个过滤器的调用        }        // We fell off the end of the chain -- call the servlet instance        try {            if (ApplicationDispatcher.WRAP_SAME_OBJECT) {                lastServicedRequest.set(request);                lastServicedResponse.set(response);            }            support.fireInstanceEvent(InstanceEvent.BEFORE_SERVICE_EVENT,                                      servlet, request, response); // Service执行前的事件            if (request.isAsyncSupported()                    && !support.getWrapper().isAsyncSupported()) {                request.setAttribute(Globals.ASYNC_SUPPORTED_ATTR,                        Boolean.FALSE);            }            // Use potentially wrapped request from this point            if ((request instanceof HttpServletRequest) &&                (response instanceof HttpServletResponse)) {                if( 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); //调用service的方法                }            } else {                servlet.service(request, response); //调用service的方法            }            support.fireInstanceEvent(InstanceEvent.AFTER_SERVICE_EVENT,                                      servlet, request, response);//service执行后的方法
OK,上面就是大致的一个过滤器链组装和调用的过程。下面我把和Filter相关的一些类抽取了出来,以便能在项目中使用到这种模式-责任链模式。
Filter:过滤器
public interface Filter {    /**     * 要执行过滤器     *     * @param request     * @param response     * @param chain     * @throws IOException     */    void doFilter(Object request, Object response,                  FilterChain chain) throws IOException;    void destory();}
FilterChain:过滤器链
public interface FilterChain {    /**     * 过滤器链,执行过滤器     * @param request     * @param response     * @throws IOException     */    void doFilter(Object request, Object response)        throws IOException;}
ApplicationFilterConfig:过滤器的一些特殊配置
public class ApplicationFilterConfig {    /**     * 设置过滤器     */    private Filter filter;    public Filter getFilter() {        return filter;    }    public ApplicationFilterConfig(Filter filter) {        this.filter = filter;    }}
ApplicationFilterChain:组装过滤器链,调用过滤器
public class ApplicationFilterChain implements FilterChain {    /**     * 执行到哪一个过滤器了     */    private int pos = 0;    /**     * 一共有组装了多少个过滤器     */    private int n = 0;    /**     * 执行完过滤器之后执行的处理类     */    private Servlet servlet;    /**     * 过滤器数组     */    private ApplicationFilterConfig[] filters = new ApplicationFilterConfig[0];    /**     * 每次增加的长度     */    public static final int INCREMENT = 10;    /**     * 过滤器链,执行过滤器     *     * @param request     * @param response     * @throws IOException     */    @Override    public void doFilter(Object request, Object response) throws IOException {        //@TODO 这里可以写一些逻辑处理        internalDoFilter(request, response);    }    public void internalDoFilter(Object request, Object response) throws IOException {        if (pos < n) {            //过滤器的处理            ApplicationFilterConfig filterConfig = filters[pos++];            Filter filter = filterConfig.getFilter();            filter.doFilter(request,response,this);            return;        }        servlet.service(request,response);    }    /**     * 添加过滤器     * @param filterConfig     */    public void addFilter(ApplicationFilterConfig filterConfig){        //过滤掉重复的Filter        for(int i=0;i<filters.length;i++){            if(Objects.equals(filters[i], filterConfig)){                return;            }        }        //数组扩容        if( n == filters.length){            ApplicationFilterConfig[] newFilters = new ApplicationFilterConfig[n + INCREMENT];            System.arraycopy(filters,0,newFilters,0,n);            filters = newFilters;        }        filters[n++] = filterConfig;    }    public void setServlet(Servlet servlet) {        this.servlet = servlet;    }    public void release() {        for (int i = 0; i < n; i++) {            filters[i] = null;        }        n = 0;        pos = 0;        servlet = null;    }}
ApplicationFilterFactory:创建过滤器链
public final class ApplicationFilterFactory {    /**     * 创建过滤器链,每个请求都会调用     * @param request     * @param wrapper     * @param servlet     */    public static ApplicationFilterChain createFilterChain(Object request, Object wrapper, Servlet servlet){        ApplicationFilterChain applicationFilterChain = new ApplicationFilterChain();        //设置Filter        ApplicationFilterConfig filterConfig = new ApplicationFilterConfig(new FirProcessFilter());        applicationFilterChain.addFilter(filterConfig);        filterConfig = new ApplicationFilterConfig(new SecProcessFilter());        applicationFilterChain.addFilter(filterConfig);        return applicationFilterChain;    }}







0 0
原创粉丝点击