一. 容器的启动过程
UML图例说明:
实心箭头表示同步调用;空心箭头表示异步调用。
图例说明:
1. 引导类Bootstrap负责引导,在其init方法内部创建容器启动所需的类加载器,以及用于JMX监控的MBeanServer
2. Bootstrap调用Catalina的load()方法加载Server的配置(也就是server.xml),将加载的配置信息委托给Digester类进行相关内容的解析。
3. Catalina获取到Server的配置信息后,执行StandardServer容器的init()方法。Tomcat的所有容器类都实现了统一的Lifecycle接口,由基类LifecycleBase提供统一的init方法来负责处理容器的状态,调用模板方法initInternal来处理各个容器自身所负责的内容。关于Tomcat的容器结构可以参看本系列文章的《Tomcat7源码解读(一)——容器静态结构概述》。StandardServer容器在其initInternal()方法中完成Mbean的设定,GlobalNamingResources的初始化和类加载器的设置。然后执行StandardService容器的init方法。
4. StandardService同StandardServer容器,由基类LifecycleBase完成容器的生命周期状态设定,而在initInternal()方法中启动Container,Executor,Connector的init方法。
5. Connector容器主要将CoyoteAdapter传递给ProtocolHandler,完成对于继续启用ProtocolHandler的初始化,关于ProtocolHandler在后面详细讲解。
6. Tomcat包含了4中不同的Container容器,从外到内分别为Engine,Host,Context,Wrapper。每一个容器都继承了ContainerBase类,在ContainerBase类的初始化中容器的启动线程,多线程异步启动各个容器。
7. StandardThreadExecutor默认情况下并不做独立的配置,而是集成在了Connector容器内部实现。
8. 在完成了对所有容器的初始化操作之后,引导类Bootstrap调用start()方法开始引导Catalina进行启动。其过程同init过程,各个容器的主要作用就是调用其子容器的start方法完成启动。与init过程一样,基类LifecycleBase提供了对于生命周期修改的统一操作,而具体的启动操作由各个容器通过模板方法startInternal()方法实现。
二. Tomcata7默认的连接器启动过程,默认情况下采用了阻塞IO的JIoEndpoint来处理请求。
1. Connector容器Service容器调用init()方法中调用模板方法initInternal()方法,并且调用Http11Protocol的init()执行初始化。
2. 这里Tomcat再次使用了模板与策略设计模式,Http11Protocol类的init方法由基类AbstractProtocol实现,主要完成了JMX的相关注册,之后开始调用核心类JIoEndpoint的初始化操作。
3. JIoEndpoint类主要通过其内部方法bind(),通过工厂ServerSocketFactory准备好serverSocket对象,完成初始化操作。
4. 完成初始化后,Connector对象,调用Http11Protocol的start()方法。
5. Http11Protocol调用JIoEndpoint类的start()方法启动Socket监听。
6. JIoEndpoint类首先创建出一个接受线程,然后启动该接受线程开始监听Socket请求。至此Connetor启动完成。
三. 接下来继续看Tomcat的请求处理过程
1. JIoEndpoint的Acceptor线程在接受到用户的请求之后,调用processSocket方法。该方法主要是从Executor线程池中获取一个线程,然后启用一个新线程执行Socket请求。实际上的处理过程要复杂的多,在多线程请求的情况下,需要考虑线程的死锁,处理请求过多时候的缓冲等内容。这里都不做说明,在后续章节详细说明。
2. JIoEndpoint在调用Http11ConnectionHandler的process方法进行处理。
3. Http11ConnectionHandler从缓冲池中取出Processor对象执行进行解析处理。
4. Http11Processor类,将socket流解析生成Request对象与Response对象。其中Request对象只是解析Header部分内容,请求参数等做延迟处理,只有在Servlet需要的时候才执行解析操作。接着就开始调用CoyoteAdapter类处理Servlet。
5. CoyoteAdapter调用容器的管道一步一步的对Request,Response对象处理。Tomcat容器主要由4层组成,通过管道的模式将各个层的功能进行了独立,也有利于对各层插入需要的功能。如果需要,只要在server.xml中加入Value元素的配置即可完成扩展功能。
6. StandardEngin容器默认管道StandardEnginValve。它主要做负责选择相应的host去处理请求。Tomcat可以有多个Host。
7. StandardHost默认情况下配置了ErrorReportValve与StandardHostValue。ErrorReportValve用于处理错误日志。StandardHostValue则选择相应的Context容器,并且设定特定的类加载器,保证Context之间的安全性。
8. StandardContext默认情况下配置了StandardContextValve。禁止对于WEB-INF与META-INF目录的访问控制,之后选择一个合适的Wrapper容器。
9. StandardWrapper容器默认情况下配置了StandardWrapperValve。主要负责了两件事情。1)是启动过滤器FilterChain,对请求执行过滤操作。2)执行service方法。如果是Jsp内容则进行编译,然后执行。如果是静态文件直接取出内容返回,如果是servlet调用那么就调用servlet方法。补充说明,StandardWrapper容器是对于Servlet的包装,所有的Request的资源可以分成4种不同的类型,静态资源请求(HTML,图片,CSS等),JSP请求,Servlet请求,以及CGI请求。对于不同的请求Tomcat用WebdavServlet处理静态资源文件,JspServlet处理Jsp请求,CGIServlet处理CGI请求。
总结:本次主要说明了Tomcat的启动过程以及与请求处理过程,很多细节的内容并没有深入展开,细节将在后续章节进行进一步的说明。