tomcat源码分析

1、运行环境

tomcat 版本:8.0.x

编译工具:ant

运行IDE:idea13.1

 

2、tomcat架构组成

如下图所示:



       Server:  其实就是BackGround程序, 在Tomcat里面的Server的用处是启动和监听服务端事件(诸如重启、关闭等命令。   

       Service: 在tomcat里面,service是指一类问题的解决方案。  通常我们会默认使用tomcat提供的:Tomcat-Standalone 模式的service。 在这种方式下的service既给我们提供解析jsp和servlet的服务, 同时也提供给我们解析静态文本的服务。  

       Connector: Tomcat都是在容器里面处理问题的, 而容器又到哪里去取得输入信息呢?

Connector就是专干这个的。 他会把从socket传递过来的数据, 封装成Request, 传递给容器来处理。  通常我们会用到两种Connector,一种叫http connectoer, 用来传递http需求的。 另一种叫AJP, 在我们整合apache与tomcat工作的时候,apache与tomcat之间就是通过这个协议来互动的。 (说到apache与tomcat的整合工作, 通常我们的目的是为了让apache 获取静态资源, 而让tomcat来解析动态的jsp或者servlet。)

        Container: 当http connector把需求传递给顶级的container: Engin的时候, 我们的视线就应该移动到Container这个层面来了。  在Container这个层, 我们包含了3种容器:Engin, Host, Context.  Engin: 收到service传递过来的需求, 处理后, 将结果返回给service( service 是通过connector 这个媒介来和Engin互动的).  Host: Engin收到service传递过来的需求后,不会自己处理, 而是交给合适的Host来处理。  Host在这里就是虚拟主机的意思, 通常我们都只会使用一个主机,既“localhost”本地机来处理。  Context: Host接到了从Host传过来的需求后, 也不会自己处理, 而是交给合适的Context来处理。

 

3、tomcat启动流程



 1> 初始化自定义的classloader

    •  根据catalina.properties的配置读取要加载的class的路径及jar包;

    •  将上述路径转化为URL集合;

    •  调用AccessController.doPrivileged生成classloader;

 

    •  设置当前上下文及对应的classloader。

 

2>使用Digester技术装配tomcat各个容器与组件

    •  创建一个Digester,并且配置好所有需要用到的actions;

    •  读取server.xml文件并将其转换为InputSource,并提供给Digester来解析成实例对象,并封装在catalina里面;

    •  最后catalina触发初始化动作,开始逐层初始化。

  

3> 初始化

        依次通过设置NEW、INITIALIZING、INITIALIZED这三个状态来表示初始化当前组件的完成。依次是server->service->engine->host->context->http connector->ajp connector。先是server初始化开始,然后是service,然后依次将里面的container初始化,然后初始化connector,其中也会初始化各种listener、manger、logger等,最后整个server才算初始化完成。在初始化StantardEngine时会创建一个线程池,用来处理HTTP请求,但此时还未启动线程。

 

4> 服务的启动

启动server及service 

        每个组件或服务的启动流程:设置STARTING_PREP状态,调用LifecycleBase的star的方法、startInternal的方法中会设置成STARTING状态,最后设置STARTED状态;其中startInternal方法的调用是其扩展点,按照上述流程会调用其内层的组件,直至所有服务或组件启动完毕。其实初始化的过程也是类似,只是调用的方法不一样而已。 

 

启动 engine(容器)

         startInternal的方法中会有各个组件自己的实现内容。从engine的启动开始(容器的启动),有所区别。它首先会启动Realm服务用来验证配置文件,用户名、密码等。然后将engine的所有容器都放到future里面,最后以异步的方式启动其子容器,然后调用pipeline,执行valve链,然后设置STARTING状态,然后启动一个线程来对当前classloader的加载进行监听从而实现可配置的热部署。  

启动mapperListener及connectors:

         mapperListener是保存了hostservice的映射关系,以保证处理请求事能找到对应的服务来处理。会按照server.xml的配置来创建指定最小和最大线程数的线程池,来接收并处理请求,超过的线程数就会排队,超过排队线程数的就会被丢弃。

        每个容器里面都会定义一个pipeline,里面会放入各种valve,每个valve都会对request进行过滤、校验等,最后都会指定下一级处理的子容器,除非到达最后一级容器context。

 

4、Tomcat处理一次请求的过程

假设来自客户的请求为:  

http://localhost:8080/test/index.jsp 

  1) 请求被发送到本机端口8080,被在那里侦听的Coyote HTTP/1.1 Connector获得   

   2) Connector把该请求交给它所在的Service的Engine来处理,并等待来自Engine的回应   

   3) Engine获得请求localhost/test/index.jsp,匹配它所拥有的所有虚拟主机Host   

   4) Engine匹配到名为localhost的Host(即使匹配不到也把请求交给该Host处理,因为该Host被定义为该Engine的默认主机)   

   5) localhost Host获得请求/test/index.jsp,匹配它所拥有的所有Context,此处为最长匹配

   6) Host匹配到路径为/test的Context(如果匹配不到就把该请求交给路径名为""的Context去处理)         7) path="/test"的Context获得请求/index.jsp,在它的mapping table中寻找对应的servlet   

   8) Context匹配到URL PATTERN为*.jsp的servlet,对应于JspServlet类   

   9) 构造HttpServletRequest对象和HttpServletResponse对象,作为参数调用JspServlet的doGet或doPost方法   

   10)Context把执行完了之后的HttpServletResponse对象返回给Host   

   11)Host把HttpServletResponse对象返回给Engine   

   12)Engine把HttpServletResponse对象返回给Connector   

   13)Connector把HttpServletResponse对象返回给客户browser

 

5、tomcat用到的主要设计模式

门面设计模式:tomcat在将http请求封装成request、response对象时,并不需要其所有的信息,所以自定义一个对象,将httprequest、httpresponse作为该对象的成员变量,然后通过这2个对象来实现自己需要的方法,避免暴露不必要的信息给外部的调用类。

命令模式(模板设计模式):所有组件都会实现同一个抽象类,像初始化、初始化完成等操作,又共同的抽象类完成,而设置内部状态的操作,由各个组件自己去实现。

责任链模式:所有容器的pipeline的实现,每个pipeline都有多个valve的定义,用来做一些过滤、校验的工作,并且在非最后一个容器的时候,会再最后一个valve指定下一个要接收的容器,从而按指定流程流转起来。

 

观察者模式:所有容器的生命周期的监听以及每个组件的状态变化及响应,像整个tomcat的初始化、加载、启动都会去修改对应组件的状态,然后将状态的变化通知给关心此状态变化的监听器。

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值