Servlet工作原理解析

 一个context对应着一个web工程

一个wrapper对应一个servlet

1.1 Servlet容器启动过程

tomcat7以后支持嵌入式功能,可直接通过构建一个tomcat对象,调用start方法启动。

添加一个web应用会调用addWebapp方法,创建一个standardContext容器,

addWebapp(Host host,String url,String path)
host:context的上层容器
url:应用的访问路径
path:应用的实际路径

Tomcat的启动逻辑是基于观察者模式设计的,所有的容器都会继承lifecycle接口,他管理容器的生命周期,所有容器的修改和状态的改变都会通知已经注册的观察者

最重要的一个配置类ContextConfig,它负责整个Web应用的配置文件的解析工作

ContextConfig的init方法主要完成以下工作:

创建解析XML配置文件的contextDigester对象

读取默认的context.xml文件,存在则解析它

读取默认的Host文件,存在则解析它

读取默认的Context自身配置文件,存在则解析它

设置Context的DocBase

ContextConfig的init完成,执行startInternal方法,主要包括:

创建资源文件对象,创建ClassLoader对象

设置对应的工作目录

启动相关辅助类

修改启动状态,通知感兴趣的观察者

子容器初始化

获取servletContext并设置必要的参数

初始化“load on startup” 的servlet

1.2 web应用初始化

Web应用初始化是在ContextConfig的configure方法实现的,主要是解析web.xml文件

Tomcat首先会找到globalWebXml,这个文件的路径是engine的工作目录下的org/apache/catalina/startup/NO_DEFAULT_XML或者conf/web.xml 。接着找hostWebXml, 这个文件在System.getProperty("catalina.base")/conf/${EngineName}/${HostName}/web.xml.default中。接着寻找应用配置文件/WEB-INF/web.xml。web.xml的各个配置项将会被解析成相应的属性保存在WebXml对象中,如果应用致辞servlet3.0,解析还将完成别的工作,比如注解的支持

servlet为什么要包装成StandardWrapper?

因为servlet是web的标准,不应强耦合在tomcat中,StandardWrapper是tomcat容器的一部分,具有容器特征

除了Servlet包装成StandardWrapper在Context容器外,其他所有的web.xml属性都被解析到Context中

1.3 创建Servlet实例

如果servlet的load-on-startup配置项大于0,那么context容器启动时就会被实例化

创建Servlet实例的方法是从Wrapper.loadSeervlet开始的,loadServlet方法要完成的就是获取servletClass,然后交给InstanceManager去创建一个机遇sevletClass.class的对象。如果配置了jsp-fle,那么这个servletClass就是JspServlet

2.1Servlet的体系结构

Servlet的规范基于ServletConfig,ServletRequest,ServletResponse这三个类运转

ServletConfig是在Servlet初始化的时候传给Servlet,而后两个值是在请求到达时调用Servlet传递过来的

StandWrapper 和 StandWrapperFacade都实现了ServletConfig的接口,StandWrapperFacade是StandWrapper的门面类,所以传给Servlet的是StandWrapperFacade对象,好处是只拿到感兴趣的数据,不会过多暴露数据

Tomcat接收请求,首先会创建org.apache.coyote.Request和Response ,这两个类是tomcat内部使用轻量级的类,只会简单解析,然后交给后续线程处理,对象很小,很容易被回收。接下来交给一个用户线程去处理这个请求,又会创建org.apache.catalina.connector.Request 和Response对象,这两个对象一直贯穿整个Servlet容器直到传给Sevelt,传递的也是门面类RequestFacade 和ResponseFacade

2.2 Servlet是如何工作的

 一个请求:http://hostname:port/contextpath/servletpath 

hostname 和port 是用来与服务器建立 TCP连接的 ,后面的url用来选择在服务器的哪个子容器中完成请求

如何确定哪个Servlet容器?

有一个mapper类保存Tomcat 和Container容器的所有子容器信息,进入Container之前Request会根据请求的hostname 和context 将host 和context容器设置到Request的mappingData属性中

2.3 Servlet中的Listener

基于观察者模式设计

servlet通过6种两类事件的观察者接口:

EventListeners:  ServeltContextAtributeListener , ServeltRequestAtributeListener ,ServeltRequestListener,  HttpSessionAtributeListener

LifecycleListeners:  ServeltContextListener  和 HttpSessionListener

 

例如常用的ContextLoaderListener实际上就是实现ServletContextListener接口,容器加载时初始化Spring容器,ContextLoaderListener在contextInitialized方法中初始化Spring容器

public void contextInitialized(ServletContextEvent event) {
        this.initWebApplicationContext(event.getServletContext());
    }

2.3 Filter如何工作

web.xml中配置<filter> 和 <filter-mapping> 使用filter 或者 实现filter接口

实现filter接口需要实现三个方法:

init:初始化

doFilter:请求来时调用,在servlet.service之前执行,使用责任链模式,可以通过FilterChain.doFilter将请求继续传递下去

destory:销毁时调用,注意,web容器调用这个方法以后,容器会再调用一次dofilter方法

Filter的核心是FilterChain对象,这个对象保存了最终Servlet对象的所有Filter对象,这些对象都在ApplicationFilterChain对象的filters数组,每执行一个filter,数组计数会加一,直到等于数组长度,执行完会执行Servlet,因此ApplicationFilterChain对象持有Servlet的引用

2.4 Servlet 中的url-pattern

servlet是通过mapper类映射,请求被创建时就已经匹配了

filter的url-pattern匹配在创建ApplicationFilterChain对象时进行,将所有filter的url-pattern与当前url匹配,匹配成功就保存到filters数组中

url-pattern匹配规则:

精确匹配:/foo.htm

路径匹配:/foo/*

后缀匹配:*.htm

Filter会将所有匹配成功的加入filters数组中

对于Servlet而言,多个匹配成功的话,优先级是:精确匹配优先,其次是最长匹配路径,最后是后缀匹配

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值