现在的位置: 首页 > 综合 > 正文

How Tomcat Works 11

2018年05月22日 ⁄ 综合 ⁄ 共 3973字 ⁄ 字号 评论关闭

一,Sequence of Methods Invocation

上图:

 

 

 

二,SingleThreadModel

之前一直有个疑问,就是servlet在容器中是每次请求都创建一个实例,还是只使用一个实例?如果是前者,那么容器中岂不是要创建N个实例;如果是后者,不同线程请求同一个servlet时的同步时如何处理的。这里就做一个详细介绍。

1,servlet在容器中只有一个实例,除非servlet实现SingleThreadModel接口。

2,不实现SingleThreadModel接口的情况下,每次用户请求servlet时,在allocate方法中先看这个instance实例是否已经存在,如果不存在就新建一个,如果存在就返回已存在实例。这种情况下,每个用户请求得到的都是同一个servlet实例,所以如果在servlet中有对公共资源或者静态变量有访问,使用者需要自己处理同步问题。

3,实现SingleThreadModel的情况,wrapper会维护一个servlet池(Stack),刚开始时池是空的,每次请求创建一个新servlet实例放入池中,再pop出来使用。之后每次先看池中有没有现成的,没有的话就继续新建,直到池满。如果一个请求过来,池中没有现成的了,都被allocate出去了,并且池已经满了,就wait,直到某个servlet在wrapper的valve中执行完毕,调用deallocate方法,把这个实例重新放回池中,以供新请求使用。

需要注意的是,SingleThreadModel只是说每个servlet实例在单独线程中执行,但是并不会解决资源的同步问题,用户仍然需要自己处理:

If a servlet implements this interface, you are guaranteed that no two threads will execute concurrently in a servlet's service method. The servlet container can guarantee this by synchronizing access to a single instance of the servlet, or by maintaining a pool of servlet instances and dispatching each new request to a free servlet. This interface does not prevent synchronization problems that result from servlets accessing shared resources such as static class variables or classes outside the scope of the servlet.

4,因为此接口容易让用户混淆,误以为是能处理同步,所以在tomcat 5之后就废除了。

 

三,StandardWrapper

前面说过,每个wrapper对应一个servlet,它负责了从load到init到allocate的一系列操作,但是对service方法的调用却是在valve里。

 

1,allocate。实际上,前面在说SingleThreadModel时,已经把allocate大致描述了,上代码吧:

分两种情况操作,比较简单不多说了。

 

2,Loading the Servlet。没什么可说的,无非就是根据servlet的全限定名,去找到相应路径load类。在load类时要区分classloader,一般情况是get到webapp的loader,再得到classloader,用它load类(见第八章)。但有几种特殊情况,一种是tomcat的org.apache.catalina.包中或实现ContainerServlet接口的servlet,二是jsp的servlet,都要用本类的classloader加载(wrapper的classloader),表明它们可以访问tomcat内部。

另外还有几点,一个是如果servlet实现ContainerServlet,则在这里((ContainerServlet) servlet).setWrapper(this);二是如果是jsp servlet,则在这调用service方法。三是如果是singleThreadModel,则之前allocate里的池是在这里new出来的。四是servlet加载后,init方法是在这里调用的servlet.init(facade)。

 

3,刚刚提到了init方法,它传递了一个ServletConfig对象,这个对象是如何生成的?其实wrapper还实现了ServletConfig,也就是说standardwrapper本身就是一个servletconfig。别的不多说了,注意一点,在init的参数中传递的是servletconfig的facade。

 

四,StandardWrapperValve

这个类负责:

1,执行这个servlet相关的filter

2,调用service方法。

 

要做到这些,必须:

1,调用wrapper的allocate,得到一个servlet实例。

2,调用createFilterChain,new一个filter chain。new的时候根据path或servlet去匹配context的filtername列表,如果匹配就加到chain中。

3,调用chian的doFilter方法,这包括调用service方法。

4,释放chain。

5,调用wrapper的deallocate方法。

说明:调用service方法,实际上是在dofilter方法中的,dofilter先把所有相关filter过滤一遍,最后在没有任何filter可调用时,调用servlet的service方法。

 

五,FilterDef,ApplicationFilterConfig和ApplicationFilterChain

1,filterdef很简单,它代表一个在web.xml里设置的filter的描述。

2,ApplicationFilterConfig这个类代表一个filter。它的getfilter方法会load这个filter。

3,chain里有个ArrayList的变量,存储filters,每次调用dofilter时,用iterator.next取得filter,调用dofilter方法,直到iterator.hasnext返回false。

 

据我得理解,容器初始化时应该是把每个app里web.xml中的filter定义都维护成一个filter表放在context中,然后在每次调用一个servlet时,从context的filter表中匹配请求的path或servlet名,如果匹配到就把这个filter放到此请求的chain中。

 

关于多个filter执行的顺序,是按照web.xml中filter-mapping出现的顺序。

【上篇】
【下篇】

抱歉!评论已关闭.