一:Servlet简介
要介绍Servlet必须从Servlet容器开始说起,Servlet与Servlet容器的关系有点像枪跟子弹的关系,枪是为子弹而生的,而子弹又让枪有了杀伤力。
以Tomcat容器为例,容器模型图大体是这样的:
从图中可以看出,Tomcate容器分为4个等级,真正管理Servlet的是Context容器,在我们实际开发中,一个web应用对应一个
Context容器,一个Wrapper对应一个Servlet,在Tomcat配置文件中很容易可以发现这一点。
二:Servlet容器的启动过程
当context容器初始状态设置Init时,添加到context容器的listener将会被调用。ContextConfig继承了LifecycleListener接口,它是在调用Tomcat.addWebapp时被加入到StandardContext容器中的。ContextConfig类会负责整个WEB应用的配置文件的解析工作。
ContextConfig的init方法将会主要完成以下工作:
- 创建用于解析XML配置文件的contextDigester对象
- 读取默认的context.xml文件,如果存在则解析它
- 读取默认的Host配置文件,如果存在则解析它
- 读取默认的Context自身的配置文件,如果存在则解析它
- 设置Context的DocBase
ContextConfig的init方法完成后,Context容器会执行startInternal方法,这个方法包括如下几个部分:
- 创建读取资源文件的对象
- 创建ClassLoader对象
- 设置应用的工作目录
- 启动相关的辅助类,如logger,realm,resources等
- 修改启动状态,通知感兴趣的观察者
- 子容器的初始化
- 获取ServletContext并设置必要的参数
- 初始化“load on startuo”的Servlet
三:Web应用的初始化工作
for (ServletDef servlet : servlets.values()) {
Wrapper wrapper = context.createWrapper();
String jspFile = servlet.getJspFile();
if (jspFile != null) {
wrapper.setJspFile(jspFile);
}
if (servlet.getLoadOnStartup() != null) {
wrapper.setLoadOnStartup(servlet.getLoadOnStartup().intValue());
}
if (servlet.getEnabled() != null) {
wrapper.setEnabled(servlet.getEnabled().booleanValue());
}
wrapper.setName(servlet.getServletName());
Map<String,String> params = servlet.getParameterMap();
for (Entry<String, String> entry : params.entrySet()) {
wrapper.addInitParameter(entry.getKey(), entry.getValue());
}
wrapper.setRunAs(servlet.getRunAs());
Set<SecurityRoleRef> roleRefs = servlet.getSecurityRoleRefs();
for (SecurityRoleRef roleRef : roleRefs) {
wrapper.addSecurityReference(
roleRef.getName(), roleRef.getLink());
}
wrapper.setServletClass(servlet.getServletClass());
MultipartDef multipartdef = servlet.getMultipartDef();
if (multipartdef != null) {
if (multipartdef.getMaxFileSize() != null &&
multipartdef.getMaxRequestSize()!= null &&
multipartdef.getFileSizeThreshold() != null) {
wrapper.setMultipartConfigElement(new
MultipartConfigElement(
multipartdef.getLocation(),
Long.parseLong(multipartdef.getMaxFileSize()),
Long.parseLong(multipartdef.getMaxRequestSize()),
Integer.parseInt(
multipartdef.getFileSizeThreshold())));
} else {
wrapper.setMultipartConfigElement(new
MultipartConfigElement(
multipartdef.getLocation()));
}
}
if (servlet.getAsyncSupported() != null) {
wrapper.setAsyncSupported(
servlet.getAsyncSupported().booleanValue());
}
context.addChild(wrapper);
}
除了将Servlet包装成StandardWrapper并作为子容器添加到Context中外,其他所有的web.xml属性都被解析到Context中。所以说
Context是真正运行Servlet的Servlet容器。一个web应用对应一个Context容器,容器的配置属性由web.xml决定,这样web.xml的作用就
显而易见了。
到目前为止已经完成了servlet的解析工作,并且被包装成了StandardWrapper添加到Context容器中,但是它仍然不能为我们
工作,因为它还没有被实例化。下一篇文章将介绍Servlet是如何被创建的以及如何被初始化的。