Servlet容器是如何工作的
Context容器直接管理Servlet的包装类Wrapper
Tomcat public addWebapp() {创建Context(StandardContext),ConextConfig配置}
ContextConfig:负责完成整个Web应用的配置文件解析工作
ContextConfig的init:{
创建用于解析XML的contextRegister对象。
读取默认的context.xml,如果存在则解析它。
读取默认的Host配置文件,如果存在则解析它。
读取默认的Context自身的配置文件,如果存在则解析它。
设置Context的DocBase。//应用实际的物理路径
}
Context容器:startInternal:
{
创建读取资源的对象
创建ClassLoader对象
设置应用的工作目录
启动相关的辅助类
修改启动状态,通知感兴趣的观察者
子容器初始化
获取Servlet并设置必要的参数
初始化Servlet(load on startup)
}
Servlet容器在web工程中是如何启动和如何解析web.xml
Web应用的初始化开始于ContextConfig.configureStart方法中实现的。主要是解析web.xml文件,web应用的关键信息,web应用的入口。
Tomcat需要globalWebXml和hostWebXml
- 查找:C:\apache-tomcat-7.0.56\conf\web.xml
- 寻找应用程序的web.xml文件,如/WEB-INF/web.xml,WebXml对象解析。
启动,
- 设置JSP
- 设置加载时启动LoadOnStartup
- 判断Servlet是否Enable
- 初始化initParameter
- 设置安全参考信息
- 设置wrapper的Class类
- 设置Servlet是否允许的文件上传的,MultiPartFile…之类的。
- 设置是否支持异步
最后添加到context托管。
for(ServletDef servlet:servlets.values){
Wrapper wrapper =context.createWrapper();
String jspFile=servlet.getJspFile();
wrapper.setJspFile(jspFile);
wrapper.setName(servlet.getServletName);
wrapper.setServletClass(servlet.getServletClass());
.....
context.addChild(wrapper);
}
这里:生成的Servlet的包装类Wrapper,而不是具体的Servlet对象,原因是Wrapper类是Tomcat容器的一部分,具有容器的特性,而Servlet是web开发的标准,不作耦合。
一个Web应用对应于一个Context容器,所以真正管理Servlet的是Context容器,容器的配置属性由web.xml设置的。
生成Servlet对象
Wrapper.loadServlet—>获取ServletClass.class—>InstanceManager生成ServletClass.class对应的对象。
**StandardContext.lifecycleEvent()–>ContextConfig.configureStart()—>webConfig—>new WebXml–>parseWebXml(globalWebXml,hostWebXml)—>configureContext()–>set(属性全设置到容器中)—>Wrapper.createWrapper()—>set(Wrapper的各种属性,包括ServletClass.class)—>
Context.addChild(wrapper)—>设置其他属性如(servletMapping)—>容器执行StartInternal==>加载资源,启动其他组件如Logger,realm==>loadOnStartup==>load。
StandardWrapper.loadServlet()–>InstanceManager.newInstance()–>initServlet()–>init(this.facade)**
this.facade是StandardWrapperFacade类实例,该类实现ServletConfig接口,并持有ServletConfig的一个实现类StandardWrapper的引用,并暴露出部分数据(足够生成Servlet)称为:门面设计模式。
用户请求是如何分配给指定Servlet的
Servlet 如何工作
http://hostname:port/contextpath/servletpath, hostname+port用于TCP连接。
org.apache.tomcat.util.http.mapper //完成根据URL选择服务器中哪种子容器来服务请求。这个类保存Tomcat中的Container所有子容器信息。在Request类进入Container容器之前,Mapper会根据Hostname和ContextPath,将hostname和context设置到Request类中的mappingData中,这样在还没有进入到Container之前就已经确定了要访问哪个容器。
为何mapper含有全部信息,原因是存在MapperListener,对容器进行监听,在容器发生变化的时候,Mapper对应的属性也会更改。
在Mapper.init过程中将host下面的子容器注册到Mapper中。
Filter如何工作
定义在web.xml的filter配置项中,和组合使用。除了Request和Response对象,还给了一个FilteChain对象,更灵活地控制跳转。
找了一个源码org\springframework\web\filter\CompositeFilter.java。然后找到doFilter方法
@Override
public void doFilter(final ServletRequest request, final ServletResponse response)
throws IOException, ServletException {
if (this.currentPosition == this.additionalFilters.size()) {
this.originalChain.doFilter(request, response);
}
else {
this.currentPosition++;
Filter nextFilter = this.additionalFilters.get(this.currentPosition - 1);
nextFilter.doFilter(request, response, this);
}
}
基本思想就是用一个position指针指向当前位置,如果filter没有到最后这接着往下执行,直到最后。
看了源码然后发现FilterChain链条的实现似曾相识,果不其然:
http://blog.csdn.net/Newpidian/article/details/53925448
这篇博客写的是实现链式AOP动态代理,实现起来的结果就像这样。
a.before()
b.before()
result=targetMethod.invokeSuper();
b.after()
a.after()