Servlet工作原理解析(三)

 上一篇文章介绍到Servlet的创建、初始化及体系架构,点这里Servlet工作原理解析(二)。本片文章将介绍Servlet两个比较常用的组件Listener和Filter以及Servlet的url-pattern。

一:Servlet的Listener
 在整个Tomcat服务器中,Listener的使用非常广泛,它是基于观察者模式所涉及的。前面文章提到过,所有的容器都会继承Life
Cycle接口,容器的变化及状态的变更会通知到已经注册的观察者(Listener)。可以说,Listener的设计为开发Servlet应用程序提供
了一种快捷的手段,能够方便的从另一个维度控制程序和数据。
 目前Servlet提供了6中两类事件的观察者接口,分别为:EventListener类型的ServletContextAttributeListener、ServletReque
stAttrubuteListener、ServletRequestListener、HttpSessionAttributeListener和LifeCycleListeners类型的ServletContextListener
、HeepSessionListener,如下图所示:
 
实际上,每个Listener都继承了EventListener接口,每个Listener各自定义了需要实现的接口,每个接口的功能在这就不详细
讲解了,感兴趣的同学可自行百度。
 它们基本涵盖了整个Servlet生命周期中你所有感兴趣的事件。这些Listener的实现类可以配置在web.xml的<listener>标签中。
当然也可以在应用程序中动态添加Listener,不过要注意的是ServletContextListener在容器启动之后就不能再添加新的,因为它监听
的事件已经不会再出现了
 如Spring的org.springframework.web.context.ContextLoaderListener就实现了ServletContextListener接口,当容器加载
时就会启动Spring容器。ContextLoaderListener在contextInitialized方法中初始化Spring容器,有几种办法可以加载Spring容器,
通过web.xml的<context-param>标签中配置Spring的applicationContext.xml的路径,文件名可以任意取,如果没有配置,将在
/WEN-INF/路径下查找默认的applicationContext.xml文件。ContextLoaderListener的contextInitialized方法源码如下:
二:Filter如何工作?
 Filter也是在web应用中常用的一个配置项,可以通过<filter>跟<filter-mapping>组合起来使用Filter。实际上Filter可以完成
与Servlet同样的工作,甚至比Servlet还灵活,因为它除了提供简单的request和response对象外,还提供了一个FilterChain对象,
这个对象可以让我们更加灵活的控制请求的流转。下图为与Filter相关的类图:

 在 Tomcat容器中,Filter Config和 Filterchain的实现类分别是 ApplicationFilterConfig和 ApplicationFilterChain,而 Filter
的实现类由用户自定义,只要实现 Filter接口中定义三个接口就行,这三个接口与在 Servlet中的类似。只不过还有一个 Application
Filterchain类,这个类可以将多个 Filter串联起来,组成一个链,这个链与 Jetty中的 Handler链有异曲同工之妙。下面详细看一下
Filter类中的三个接口方法。
  • init(FilterConfig):初始化接口,在用户自定义的 Filter初始化时被调用,它与Servlet的int方法的作用是一样,FilterConfig与 Servletconfig也类似,除了都能取到容器的环境类 Servletcontext对象之外,还能获取在< filter>下配置的<init-param>参数值。
  • do Filter( Servletrequest,Servletresponse,Filterchain):在每个用户的请求进来时这个方法都会被调用,并在 Servlet的 service方法之前被调用。而 FilterChain就代表当前的整个请求链,所以通过调用 FilterChain.doFilter可以将请求继续传递下去。如果想拦截这个请求,可以不调用 FilterChain.dofilter,那么这个请求就直接返回了。所以 Filter是一种责任链设计模式。
  • destroy:当 Filter对象被销毁时,这个方法被调用。注意,当Web容器调用这个方法之后,容器会再调用一次 dofilter方法。

 Filter类的核心还是传递的FilterChain对象,这个对象保存了到最终Servlet对象的所有Filter对象,这些对象都保存在 Applica
tionFilterChain对象的filters数组中。在 Filterchain链上每执行一个Filter对象,数组的当前计数都会加1,直到计数等于数组的长
度,当Filterchain上所有的 Filter对象执行完成后,就会执行最终的 Servlet。所以在 ApplicationFilterchain对象中会持有 Servlet
对象的引用。下图是Filter对象的执行时序图。


 Filter存在的意义就像你从上海出发到北京,可以在路上添加一点东西或者是扔掉一些东西,filter的机制就是可以让你自定义
一些拦截工作。
三:Servlet中的url-pattern
 在web.xml中<servlet-mapping>和<filter-mapper>都有<url-pattern>配置项,它们的作用都是匹配一次请求是否会执行 这个Servlet和Filter,那么这个URL是怎么匹配的呢,又是何时匹配的呢?
 先看看 Servlet是何时匹配的。在上篇文章中介绍了一个请求最终被分配到一个 servlet中是通过org.apache.tomcat.util.http.
Mapper类完成的,这个类会根据请求的URL来匹配在 每个Servlet中配置的<url-pattern>,所以它在一个请求被创建时就已经匹配
了。
 Filter的 url-pattern配是在创建ApplicationFilterChain对象时进行的,它会把所有定义的Filter的url-pattern与当前的URL 匹配,如果匹配成功就将这个 Filter保存到ApplicationFilterChain的Filters数组中,然后在FilterChain中依次调用。
 在web.xml加载时,会首先检查<url-pattern>配置是否符合规则,这个检查是在StandardContext的validateURLPattern方法
中检查的,如果检查不成功, Context容器启动会失败,并且会报 java.lang.illegalArgumentException:Invalid<url-pattern>/a/*
.htm in Servlet mapping错误。
 <url-pattern>的解析规则,对 Servlet和 Filter是一样的,匹配的规期有如下三种:
  • 精确匹配:如 /foo.htm只会匹配foo.htm这个URL。
  • 路径匹配:如/foo/*会匹配以foo为前缀的URL。
  • 后缀匹配:如*.htm会匹配所有以htm为后缀的URL。
 Servlet的匹配规则在 org. apache, tomcat, utilhttp. mapper. Mapper.internalmap Wrapper中定义,对Servlet的匹
配来说如果同时定义了多个<url-pattern>,那么到底匹配那个Servlet呢?这个匹配的顺序是:首先精确匹配,如定义了两个
Servlet,Servlet1为 /foo.htm,Servlet2是/*,请求URL为 http://localhost/foo.htm,那么只有 Servlet1匹配成功;如果精
确匹配不成功,那么会使用二个原则“最长路径匹配”,如 Servlet1为foo/*,Servlet2为/*,这时请求的URL为http:localho
st/foo/foo.htm,那么 Servlet1匹配成功;最后根据后进行匹配,但是一次请求只会成功匹配到一个 Servlet。
 Filer的匹配规则在 ApplicationFilterFactory.matchFiltersURL方法中定义,Filter的匹配原则和 Servlet有些不同,只要
匹配成功,这些 Filter都会在请求链上被调用,<url-pattern>的其他写法(如/foo/、/*.htm和*/foo)都是不对的。

四:关于Servlet的总结
   关于书中Servlet的介绍就到此结束了,整理到博客上来加起来有三篇,从Servlet容器的启动、初始化到Serlvet的创建、初始
化及Servlet的体系结构,再到Servlet常用的listener及filter组件大体总结完了,其中多数是书上的原文,搬到博客上来的目的是希望
自己能够对看过去的东西有个整体的把握。
 文章如有错误之处,还请各位路过的大神指出,也希望自己能坚持总结下去。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值