How Tomcat Works(十四)中,本人并没有对javax.servlet.Filter及javax.servlet.FilterChain做详细的描述,本文在这里做一下补充

FilterChain接口只有一个方法,方法声明如下:

public void doFilter ( ServletRequest request, ServletResponse response ) throws IOException, ServletException;

在tomcat中,org.apache.catalina.core.ApplicationFilterChain类实现了该接口

ApplicationFilterChain类采用一个私有成员变量private ArrayList filters = new ArrayList()保存ApplicationFilterConfig对象的集合,ApplicationFilterConfig类实现了javax.servlet.FilterConfig接口,封装了对Filter实例的管理

下面是向ArrayList filters集合添加ApplicationFilterConfig实例

void addFilter(ApplicationFilterConfig filterConfig) {

        this.filters.add(filterConfig);

    }

setServlet()方法用于向ApplicationFilterChain对象设置当前的servlet实例

void setServlet(Servlet servlet) {

        this.servlet = servlet;

    }

在ApplicationFilterChain类的实现FilterChain接口方法doFilter()中,调用了其私有方法internalDoFilter(),下面是该方法的具体实现

private void internalDoFilter(ServletRequest request, ServletResponse response)
throws IOException, ServletException { // Construct an iterator the first time this method is called
if (this.iterator == null)
this.iterator = filters.iterator(); // Call the next filter if there is one
if (this.iterator.hasNext()) {
ApplicationFilterConfig filterConfig =
(ApplicationFilterConfig) iterator.next();
Filter filter = null;
try {
filter = filterConfig.getFilter();
support.fireInstanceEvent(InstanceEvent.BEFORE_FILTER_EVENT,
filter, request, response);
filter.doFilter(request, response, this);
support.fireInstanceEvent(InstanceEvent.AFTER_FILTER_EVENT,
filter, request, response);
} catch (IOException e) {
if (filter != null)
support.fireInstanceEvent(InstanceEvent.AFTER_FILTER_EVENT,
filter, request, response, e);
throw e;
} catch (ServletException e) {
if (filter != null)
support.fireInstanceEvent(InstanceEvent.AFTER_FILTER_EVENT,
filter, request, response, e);
throw e;
} catch (RuntimeException e) {
if (filter != null)
support.fireInstanceEvent(InstanceEvent.AFTER_FILTER_EVENT,
filter, request, response, e);
throw e;
} catch (Throwable e) {
if (filter != null)
support.fireInstanceEvent(InstanceEvent.AFTER_FILTER_EVENT,
filter, request, response, e);
throw new ServletException
(sm.getString("filterChain.filter"), e);
}
return;
} // We fell off the end of the chain -- call the servlet instance
try {
support.fireInstanceEvent(InstanceEvent.BEFORE_SERVICE_EVENT,
servlet, request, response);
if ((request instanceof HttpServletRequest) &&
(response instanceof HttpServletResponse)) {
servlet.service((HttpServletRequest) request,
(HttpServletResponse) response);
} else {
servlet.service(request, response);
}
support.fireInstanceEvent(InstanceEvent.AFTER_SERVICE_EVENT,
servlet, request, response);
} catch (IOException e) {
support.fireInstanceEvent(InstanceEvent.AFTER_SERVICE_EVENT,
servlet, request, response, e);
throw e;
} catch (ServletException e) {
support.fireInstanceEvent(InstanceEvent.AFTER_SERVICE_EVENT,
servlet, request, response, e);
throw e;
} catch (RuntimeException e) {
support.fireInstanceEvent(InstanceEvent.AFTER_SERVICE_EVENT,
servlet, request, response, e);
throw e;
} catch (Throwable e) {
support.fireInstanceEvent(InstanceEvent.AFTER_SERVICE_EVENT,
servlet, request, response, e);
throw new ServletException
(sm.getString("filterChain.servlet"), e);
} }

在调用了filter.doFilter(request, response, this)方法之后,继续执行servlet的service()方法

这里的this是ApplicationFilterChain对象自身,在我们编写的Filter实现类里面同在在执行完我们实现的过滤方法之后会继续调用FilterChain对象的void doFilter(ServletRequest request, ServletResponse response)方法,我们自定义的过滤器通常会这样实现:

class SampleFilter implements Filter {
........
public void doFilter(ServletRequest request, ServletResponse response,FilterChain chain)
throws IOException, ServletException { //do something
.....
//request, response传递给下一个过滤器进行过滤
chain.doFilter(request, response);
} }

ApplicationFilterConfig类实现了javax.servlet.FilterConfig接口,代表一个Filter容器,FilterConfig接口定义如下:

public interface FilterConfig {    

    public String getFilterName(); 

    public ServletContext getServletContext();    

    public String getInitParameter(String name);   

    public Enumeration getInitParameterNames();
}

可以通过传入org.apache.catalina.Context对象和FilterDef对象(FilterDef对象用于对过滤器类的定义,包括过滤器类名、相关参数等)传给其构造函数构造一个ApplicationFilterConfig对象:

public ApplicationFilterConfig(Context context, FilterDef filterDef)
throws ClassCastException, ClassNotFoundException,
IllegalAccessException, InstantiationException,
ServletException { super();
this.context = context;
setFilterDef(filterDef); }

ApplicationFilterConfig类的getFilter()方法返回一个javax.servlet.Filter对象,该方法负责载入并实例化一个过滤器类

Filter getFilter() throws ClassCastException, ClassNotFoundException,
IllegalAccessException, InstantiationException, ServletException { // Return the existing filter instance, if any
if (this.filter != null)
return (this.filter); // Identify the class loader we will be using
String filterClass = filterDef.getFilterClass();
ClassLoader classLoader = null;
if (filterClass.startsWith("org.apache.catalina."))
classLoader = this.getClass().getClassLoader();
else
classLoader = context.getLoader().getClassLoader(); ClassLoader oldCtxClassLoader =
Thread.currentThread().getContextClassLoader(); // Instantiate a new instance of this filter and return it
Class clazz = classLoader.loadClass(filterClass);
this.filter = (Filter) clazz.newInstance();
filter.init(this);
return (this.filter); }

现在,也许我们更容易理解StandardWrapperValve类中创建过滤器链createFilterChain()方法了

private ApplicationFilterChain createFilterChain(Request request,
Servlet servlet) { // If there is no servlet to execute, return null
if (servlet == null)
return (null); // Create and initialize a filter chain object
ApplicationFilterChain filterChain =
new ApplicationFilterChain();
filterChain.setServlet(servlet);
StandardWrapper wrapper = (StandardWrapper) getContainer();
filterChain.setSupport(wrapper.getInstanceSupport()); // Acquire the filter mappings for this Context
StandardContext context = (StandardContext) wrapper.getParent();
FilterMap filterMaps[] = context.findFilterMaps(); // If there are no filter mappings, we are done
if ((filterMaps == null) || (filterMaps.length == 0))
return (filterChain);
// if (debug >= 1)
// log("createFilterChain: Processing " + filterMaps.length +
// " filter map entries"); // Acquire the information we will need to match filter mappings
String requestPath = null;
if (request instanceof HttpRequest) {
HttpServletRequest hreq =
(HttpServletRequest) request.getRequest();
String contextPath = hreq.getContextPath();
if (contextPath == null)
contextPath = "";
String requestURI = ((HttpRequest) request).getDecodedRequestURI();
if (requestURI.length() >= contextPath.length())
requestPath = requestURI.substring(contextPath.length());
}
String servletName = wrapper.getName();
// if (debug >= 1) {
// log(" requestPath=" + requestPath);
// log(" servletName=" + servletName);
// }
int n = 0; // Add the relevant path-mapped filters to this filter chain
for (int i = 0; i < filterMaps.length; i++) {
// if (debug >= 2)
// log(" Checking path-mapped filter '" +
// filterMaps[i] + "'");
if (!matchFiltersURL(filterMaps[i], requestPath))
continue;
ApplicationFilterConfig filterConfig = (ApplicationFilterConfig)
context.findFilterConfig(filterMaps[i].getFilterName());
if (filterConfig == null) {
// if (debug >= 2)
// log(" Missing path-mapped filter '" +
// filterMaps[i] + "'");
; // FIXME - log configuration problem
continue;
}
// if (debug >= 2)
// log(" Adding path-mapped filter '" +
// filterConfig.getFilterName() + "'");
filterChain.addFilter(filterConfig);
n++;
} // Add filters that match on servlet name second
for (int i = 0; i < filterMaps.length; i++) {
// if (debug >= 2)
// log(" Checking servlet-mapped filter '" +
// filterMaps[i] + "'");
if (!matchFiltersServlet(filterMaps[i], servletName))
continue;
ApplicationFilterConfig filterConfig = (ApplicationFilterConfig)
context.findFilterConfig(filterMaps[i].getFilterName());
if (filterConfig == null) {
// if (debug >= 2)
// log(" Missing servlet-mapped filter '" +
// filterMaps[i] + "'");
; // FIXME - log configuration problem
continue;
}
// if (debug >= 2)
// log(" Adding servlet-mapped filter '" +
// filterMaps[i] + "'");
filterChain.addFilter(filterConfig);
n++;
} // Return the completed filter chain
// if (debug >= 2)
// log(" Returning chain with " + n + " filters");
return (filterChain); }

---------------------------------------------------------------------------

本系列How Tomcat Works系本人原创

转载请注明出处 博客园 刺猬的温驯

本人邮箱: chenying998179#163.com (#改为@)

本文链接http://www.cnblogs.com/chenying99/p/3250342.html

How Tomcat Works(十四)补充的更多相关文章

  1. How Tomcat Works(四)

    Servlet容器有两个主要的模块,即连接器(connector)与容器(container),本文接下来创建一个连接器来增强前面文章中的应用程序的功能,以一种更优雅的方式来创建request对象和r ...

  2. 攻城狮在路上(伍)How tomcat works(四)Tomcat的默认连接器

     在第4章中将通过剖析Tomcat4的默认连接器的代码,讨论需要什么来创建一个真实的Tomcat连接器.     注意:本章中提及的“默认连接器”是指Tomcat4的默认连接器.即使默认的连机器已经被 ...

  3. How Tomcat Works(十四)

    我们已经知道,在tomcat中有四种类型的servlet容器,分别为Engine.Host.Context 和Wrapper,本文接下来对tomcat中Wrapper接口的标准实现进行说明. 对于每个 ...

  4. How Tomcat Works(十八)

    在前面的文章中,如果我们要启动tomcat容器,我们需要使用Bootstrap类来实例化连接器.servlet容器.Wrapper实例和其他组件,然后调用各个对象的set方法将它们关联起来:这种配置应 ...

  5. (C/C++学习笔记) 二十四. 知识补充

    二十四. 知识补充 ● 子类调用父类构造函数 ※ 为什么子类要调用父类的构造函数? 因为子类继承父类,会继承到父类中的数据,所以子类在进行对象初始化时,先调用父类的构造函数,这就是子类的实例化过程. ...

  6. How Tomcat Works(二十)

    要使用一个web应用程序,必须要将表示该应用程序的Context实例部署到一个host实例中.在tomcat中,context实例可以用war文件的形式来部署,也可以将整个web应用拷贝到Tomcat ...

  7. How Tomcat Works(十九)

    本文重点关注启动tomcat时会用到的两个类,分别为Catalina类和Bootstrap类,它们都位于org.apachae.catalina.startup包下:Catalina类用于启动或关闭S ...

  8. How Tomcat works — 四、tomcat启动(3)

    上一节说到StandardService负责启动其子组件:container和connector,不过注意,是有先后顺序的,先启动container,再启动connector,这一节先来看看conta ...

  9. How Tomcat Works(十六)

    本文接下来会介绍Host容器和Engine容器,在tomcat的实际部署中,总是会使用一个Host容器:本文介绍Host接口和Engine接口及其相关类 Host容器是org.apache.catal ...

随机推荐

  1. OC获取文件(夹)的代码行数

    /* 考察NSString NSArray NSFileManager */ #import <Foundation/Foundation.h> /* 计算单个文件的代码行数 path:文 ...

  2. 旧书重温:0day2【2】 实验:三种获取kernel32.dll基址的方法

    0x01 找kernel32基地址的方法一般有三种: 暴力搜索法.异常处理链表搜索法.PEB法. 0x02 基本原理 暴力搜索法是最早的动态查找kernel32基地址的方法.它的原理是几乎所有的win ...

  3. SAS9.4 安装注意事项

    OS:Windows Server 2012 R2 SAS:9.4 TS1M1 SAS9.4的安装需要注意的地方: 一. 注意开启Shortname(装了N遍,最容易忘记的地方) SAS安装使用Sho ...

  4. 配置java环境时,java的path地址放在其他地址的前面还是后面?

      PATH环境变量里是按顺序查找的,如果电脑里只有一个jdk,放哪都一样,有多个放前面的会优先.   一般是放在最前面吧,以免其他在path中的程序需要用到Java环境而由于在JAVA_PATH之前 ...

  5. 25个有用的jQuery日历和日期选取插件

    jQuery被认为是最好的JavaScript库,因为它简单易用.灵活,并有大量的插件.本文介绍25个非常不错的jQuery日历和日期选取插件,希望对各位有用. 1. Simple JQuery Da ...

  6. PHP中超全局变量$GLOBALS和global的区别

    一.超全局变量$GLOBALS PHP超全局变量有很多,如下的都属于超全局变量(Superglobal): $GLOBALS,$_SERVER,$_GET,$_POST,$_FILES,$_COOKI ...

  7. myeclipse10添加jQuery自动提示

    首先先要在装上spket插件,这个网上有好多教程,我就不详细说了,主要说一下后面的设置,因为我发现我按照网上的装完也设置完没办法使用自动提示功能,以下是我根据前辈的经验然后自己摸索出来的: 选中所建的 ...

  8. jQuery插件开发的模式和结构

    jQuery插件开发 一般来说,jQuery插件的开发分为两种:一种是挂在jQuery命名空间下的全局函数,也可称为静态方法:另一种是jQuery对象级别的方法,即挂在jQuery原型下的方法,这样通 ...

  9. js document对象

    document对象可以通过多种方式获取: 最常见的一种情况是,你在文档的script脚本中直接使用document,这个document代表运行着该脚本的文档.(这个document和window. ...

  10. bzoj1391 最大权闭合子图(also最小割、网络流)

    一道裸的最小割的题,写一下只是练练手. 表示被卡M,RE不开心.一道裸题至于吗? 再次复习一下最大权闭合子图: 1.每一个点若为正权,与源点连一条容量为绝对值权值的边.否则连向汇点一条容量为绝对值权值 ...