您的位置:首页 > 其它

Servlet 工作原理解析

2014-02-27 22:59 357 查看

1.Servlet 容器

从上图可以看出 Tomcat
的容器分为四个等级,真正管理 Servlet
的容器是 Context容器,一个servlet容器管理多个项目,一个 Context
对应一个 Web
工程,在 Tomcat的配置文件中可以很容易发现这一点,如下:
<?xml version='1.0'encoding='utf-8'?>
<Server port="8005"shutdown="SHUTDOWN">
<Servicename="Catalina">
<Connectorport="8080"protocol="HTTP/1.1"connectionTimeout="20000"redirectPort="8443" URIEncoding="UTF- 8"/>
<Enginename="Catalina"defaultHost="localhost">
<Host name="localhost">
<Context docBase="test_session"path="/test_session" reloadable="true"source="org.eclipse.jst.jee.server:test_session"/></Host>
// 此处可以写多个context
</Host>
</Engine>
</Service>
</Server>

2.Servlet 容器的启动过程

启动类org.apache.catalina.startup.Tomcat。创建一个实例对象并调用 start 方法就可以很容易启动Tomcat。
利用这个 Tomcat 类来管理新增的一个 Context容器,将工程加到这个Context 容器。
然后tomcat启动(容器启动),会做包括如下的工作:
1.获取 ServletContext
并设置必要的参数
2.实例化并初始化“load on startup”的 Servlet
1\
Context ctx = new StandardContext();

ctx.setPath( url );
ctx.setDocBase(path);
所有的容器都会继承 Lifecycle接口,这个接口管理着容器的整个生命周期。所有容器的修改和状态的改变都会由Lifecycle去通知已经注册的观察者(Listener)。

2\
ContextConfig ctxCfg = newContextConfig();

ctxCfg.setDefaultWebXml("org/apache/catalin/startup/NO_DEFAULT_XML");
ctx.addLifecycleListener(ctxCfg);

ContextConfig 继承了 LifecycleListener 接口,ContextConfig 将会负责整个 Web应用配置的解析工作。

3\
if (host == null) {

getHost().addChild(ctx);

} else {
host.addChild(ctx);
}
当 Context 容器初始化状态设为 init 时,添加在 Contex 容器的 Listener将会被调用,即ContextConfig 解析web应用的配置工作。

3.Web 应用的初始化工作

Web 应用的初始化工作是在 ContextConfig 的 configureStart 方法中实现的,应用的初始化主要是要解析web.xml 文件,这个文件描述了一个 Web 应用的关键信息,也是一个 Web 应用的入口。

web.xml 文件中的各个配置项将会被解析成相应的属性保存在 WebXml对象中,接下去将会将 WebXml 对象中的属性设置到Context 容器中.

这段代码在 WebXml 的 configureContext 方法中。

比如一个Servlet,会被包装成Wrapper类,Wrapper包含Servlet中的信息,再加入到Context中。context.addChild(wrapper);

===

4.创建 Servlet 实例及初始化

步骤如下:
1. 解析web.xml中的servlet:将Servlet包装成Wrapper ->context.addChild(Wrapper),放入容器中
2. 创建servlet对象: wrapper.loadServlet() ---servletClass--->InstaceManager.instance(Class servletClass)
3. 初始化对象:StandardWraper.initServlet() ->Servlet.init() ->将ServletConfig传给servlet对象。
servlet会在以下的两个情况下被初始化:
情况一:如果该servlet的load-on-starup值>0,context 容器启动的时候就会被初始化。
顺序是由小到大,正整数小的先被实例化。
load-on-starup=0时,web容器启动的时候做实例化处理,相当于是最大整数,因此web容器启动时,最后被实例化。
情况二:如果load-on-starup<0,或者没有设置,servlet首次被调用时做实例化。

5.Servlet 体系结构

门面模式:/article/5110140.html
与 Servlet
主动关联的是三个类,分别是 ServletConfig、ServletRequest
和ServletResponse。
1、ServletConfig:获取这个Servlet
的一些配置属性,而这些配置属性可能在 Servlet
运行时被用到。 Servlet初始化时就传给 Servlet
了。

StandardWrapper
和 StandardWrapperFacade
都实现了ServletConfig
接口,而 StandardWrapperFacade
是 StandardWrapper
门面类。所以传给 Servlet
的是 StandardWrapperFacade对象,这个类能够保证从 StandardWrapper
中拿到 ServletConfig
所规定的数据,而又不把ServletConfig
不关心的数据暴露给 Servlet。

2、ServletContext : 可以拿到Context
容器中一些必要信息,比如应用的工作路径,容器支持的 Servlet
最小版本等(一个交易场景,这个场景一直跟随个这个交易过程直到这个交易完成为止。)
Servlet
中能拿到的 ServletContext
的实际对象也是 ApplicationContextFacade对象。ApplicationContextFacade
同样保证 ServletContex只能从容器中拿到它该拿的数据,它们都起到对数据的封装作用,它们使用的都是门面设计模式。

3、 ServletRequest和 ServletResponse
就是要交互的具体对象。作为运输工具来传递交互结果。是在请求达到时调用Servlet
时传递过来的。
为何 Context
容器传过来的 ServletRequest、ServletResponse
可以被转化为HttpServletRequest
和 HttpServletResponse
呢?

Tomcat
一接受到请求首先将会创建 org.apache.coyote.Request/Response,接下去当交给一个用户线程去处理这个请求时又创建org.apache.catalina.connector.Request /Response.这两个对象一直穿越整个Servlet
容器直到要传给 Servlet,传给 Servlet
的是 Request
和 Response
的门面类RequestFacade
和RequestFacade,这里使用门面模式与前面一样都是基于同样的目的——封装容器中的数据。

6.Servlet如何工作

基本步骤:
http://hostname: port/contextpath/servletpath
request.getHost() : Host
容器
request.getContext: context容器
request.wrapper: wrapper容器,从而找到具体的servlet,执行service方法。
当 Servlet 从 Servlet 容器中移除时,也就表明该 Servlet 的生命周期结束了,这时
Servlet 的 destroy 方法将被调用,做一些扫尾工作。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: