一、从servlet容器说起
Servlet容器有很多种实现,比如:Jetty、Tomcat,这里以Tomcat为例介绍。在Tomcat的容器等级中,Context容器直接管理Servlet在容器中的包装类Wrapper,所以Context容器如何运行将直接影响Servlet的工作方式。Tomcat容器模型如下图:
从上图可以看出,Tomcat的容器分为4个等级,真正管理Servlet的容器是Context容器,一个Context对应一个Web工程,在Tomcat的配置文件中可以很容易地防线这一点:
下面详细介绍Tomcat解析Context容器的过程,包括如何构建Servlet。
1、servlet容器的启动过程
从Tomcat 7开始支持嵌入式功能,即增加了一个启动类org.apache.catalina.startup.Tomcat。创建一个实例对象并调用start方法就可以很容易地启动Tomcat。我们还可以通过这个对象来增加和修改Tomcat的配置参数,如可以动态增加Context、servlet等。
Tomcat的启动逻辑是基于观察者模式设计的,所有的容器都会继承Lifecycle接口,它管理着容器的整个生命周期,所有容器的修改和状态的改变都会由它去通知已经注册的观察者(Listener)。Tomcat启动的时序图如下:
2、web应用的初始化工作
Web应用的初始化工作是在ContextConfig的configureStart方法中实现的,应用的初始化主要是解析web.xml文件,这个文件描述了一个Web应用的关键信息,也是一个Web应用的入口。web.xml文件中的各个配置项将会解析成相应的属性保存在WebXml对象中。WebXml对象中的属性又会被设置到Context容器中,这里包括创建Servlet对象、filter、listener等,所以说Context容器才是真正运行Servlet的Servlet容器。一个Web应用对应一个Context容器,容器的配置属性由应用的web.xml指定。
二、创建servlet实例
1、创建servlet对象
如果Servlet的load-on-startup配置项大于0,那么在Context容器启动时就会被实例化,默认会启动两个Servlet,分别是org.apache.catalina.servlets.defaultServlet和org.apache.jasper.servlet.JspServlet,它们的load-on-startup分别是1和3。
创建Servlet实例的方法是从Wrapper.loadServlet开始的。loadServlet方法要完成的就是获取servletClass,然后把它交给InstanceManager去创建一个机遇servletClass.class的对象。如果这个Servlet配置了jsp-file,那么这个servletClass就是在conf/web.xml中定义的org.apache.jasper.servlet.JspServlet了。
2、初始化servlet
初始化Servlet在StandardWrapper的initServlet方法中,这个方法调用Servlet的init()方法,同时把StandardWrapper对象的StandardWrapperFacade作为ServletConfig传给Servlet。如果该Servlet关联的是一个JSP文件,那么前面初始化的就是JspServlet,接下来会模拟一次简单请求,请求调用这个JSP文件,以便编译这个JSP文件为类,并初始化这个类。这样Servlet对象就初始化完成了。
三、servlet体系结构
Servlet顶层类的关联图如下:
从上图可以看出,与Servlet主动关联三个类分别是ServletConfig、ServletRequest和ServletResponse。
一次请求对应的Request和Response的类转化如下图:
四、servlet如何工作
用户从浏览器向服务器发起的一个请求通常会包含如下信息:,hostname和port用来与服务器建立TCP连接,后面的URL才用来选择在服务器中哪个子容器服务用户的请求。在Tomcat中URL与Servlet容器通过类org.apache.tomcat.util.http.mapper来完成映射,Mapper会根据请求的hostname和contextpath将host和context容器设置到Request的mappingData属性中。
Servlet能帮我们完成所有工作,但是现在的Web应用很少直接将交互的全部页面用Servlet来实现,而是采用更加高效的MVC框架来实现。这些MVC框架的基本原理是将所有的请求都映射到一个Servlet,然后去实现service方法,这个方法也就是MVC框架的入口。
当Servlet从Servlet容器中移除时,也表明该Servlet的生命周期结束了,这时Servlet的destroy方法将被调用,做一些扫尾工作。
五、servlet中的listener
在整个Tomcat服务器中,Listener使用非常广泛,它是基于观察者模式设计的,Listener的设计为开发Servlet应用程序提供了一种快捷的手段,能够方便地从另一个纵向维度控制程序和数据。目前在Servlet中提供了下图所示的类型:
它们基本上涵盖了整个Servlet生命周期中你感兴趣的每种事件,这些Listener的实现类可以配置在web.xml
标签中,当然也可以在应用程序中添加Listener,但是ServletContextListener在容器启动之后就不能再添加新的了,因为它所监听的事件已经不会再出现了。
六、filter如何工作
Filter也是在web.xml中另一个常用的配置项,可以通过和组合来使用Filter。实际上Filter可以完成与Servlet同样的工作,甚至比其更加灵活,因为它除了提供request和response对象外,还提供了一个FilterChain对象,这个对象可以让我们更加灵活地控制请求的流转。下面是与Filter相关的类结构图:
Filter存在的意义就好比是你要去北京,它是你的目的地,但是提供了一个机制让你在去的途中可以做一些拦截工作,如可以将你的一些行李包存放在某个地方,当你返回时你可以再从这个地方取回,即可以让你在途中增加或者减少一些东西。
七、servlet中的url-pattern
在web.xml中和都有配置项,它们的作用都是匹配一次请求是否会执行这个Servlet或者Filter。
一个请求最终被分配到一个Servlet中是通过org.apache.tomcat.util.http.Mapper类完成的,这个类会根据请求到的URL来匹配在每个Servlet中配置的,所以它在一个请求被创建时就已经匹配了。
Filter的url-pattern匹配是在创建ApplicationFilterChain对象时进行的,它会把所有定义的Filter的url-pattern与当前的URL匹配,如果匹配成功就将这个Filter保存到ApplicationFilterChain的filters数组中,然后在FilterChain中依次调用。
在web.xml加载时,会首先检查配置是否符合规则,这个检查是在StandardContext的validateURLPattern方法中检查的,如果检查不成功,Context容器启动会失败,并且会报java.lang.IllegalArgumentException:Invalid/a/*.htm in Servlet mapping错误。
的匹配规则有如下3种:
(1)精确匹配:如/foo.htm只会匹配foo.htm这个URL。
(2)路径匹配:如/foo/*会匹配以foo为前缀的URL。
(3)后缀匹配:如*.htm会匹配所有以.htm为后缀的URL。
阅读(4731) | 评论(0) | 转发(0) |