Tomcat历史
Tomcat最初有sun公司的架构师James Duncan Davidson开发,名称“JavaWebServer” 1999与Apache软件基金会旗下的JServ项目合并,也就是Tomcat。2001 tomcat4.0 里程碑式的版本。完全重新设计了其架构,并实现了Servlet2.3和JSP 1.2规范。到目前,Tomcat已经成为成熟的Servlet容器产品,并作为 JBoss等应用的服务器的内嵌Servlet容器。
总体结构(结构演变理解)
1、最简单的结构
Server
接受请求并解析,完成相关任务,返回处理结果通常情况下使用Socket监听服务器指定端口来实现该功能,一个最简单的服务设计如下方法:
- Start():启动服务器,打开socket连接,监听服务端口,接受客户端请求、处理、返回响应
- Stop():关闭服务器,释放资源
缺点:请求监听和请求处理放一起扩展性很差(协议的切换 tomcat独立部署使用HTTP协议,与Apache集成时使用AJP协议)
改进:网络协议与请求处理分离
2、Connector和Container
一个Server包含多个Connector(链接器)和Container(容器)
Connector:开启Socket并监听客户端请求,返回响应数据;Container:负责具体的请求处。
缺点:Connector接受的请求由那个Container处理,需要建立映射规则
改进:一个Server可以包含多个Service,每一个Service都是独立的,他们共享一个JVM以及系统类库。
3、Server包含多个Service
一个Service负责维护多个Connector和一个Container,这样来自Connector的请求只能有它所属的Service维护的Container处理。
在这里Container是一个通用的概念,为了明确功能,并与Tomcat中的组件名称相同,可以将Container命名为Engineer
4、Engine、Context
在Engine容器中需要支持管理WEB应用,当接收到Connector的处理请求时,Engine容器能够找到一个合适的Web应用来处理,因此在上面设计的基础上增加Context来表示一个WEB应用,并且一个Engine可以包含多个Context。
缺点:应用服务器需要将每个域名抽象为一个虚拟主机,
5、Host、Wrapper
通常在一个主机下,提供多个域名的服务,因此引入Host
在一个web应用中,可以包含多个Servlet实例来处理来自不同的链接请求,因此我们还需要一个组件概念来表示Servlet定义,即Wrapper。
在前面的Container容器中,Engine、Host、Context、Wrapper是一类组件,这类组件的作用就是处理接收客户端的请求并且返回响应数据,并且有可能请求到Engine容器,Engine容器委托给子容器Host处理。
使用Container代表容器,Engine、Host、Context、Wrapper都是Container的子容器,Container可以维护子容器。backgroundProcess()方法针对后台处理,并且其基础抽象类(ContainerBase)确保在启动组件的同时,异步启动后台处理。
容器之间的组合关系是一种弱依赖,用虚线表示。
每一个组件都有启动、停止等生命周期方法,拥有生命周期的特征。所以定义一个通用的LifeCycle接口,
架构
连接器Connector
1 | 监听服务器端口,读取来自客户端的请求 |
连接器需要完成 3 个高内聚的功能:
- 网络通信。
- 应用层协议解析。
- Tomcat Request/Response 与 ServletRequest/ServletResponse 的转化。
因此 Tomcat 的设计者设计了 3 个组件来实现这 3 个功能,分别是 EndPoint、Processor 和 Adapter。
Endpoint 和 Processor 放在一起抽象成了 ProtocolHandler 组件,连接器用 ProtocolHandler 来处理网络连接和应用层协议。
EndPoint 是一个接口,它的抽象实现类 AbstractEndpoint 里面定义了两个内部类:Acceptor 和 SocketProcessor。其中 Acceptor 用于监听 Socket 连接请求。SocketProcessor 用于处理接收到的 Socket 请求。
EndPoint 接收到 Socket 连接后,生成一个 SocketProcessor 任务提交到线程池去处理,SocketProcessor 的 Run 方法会调用 Processor 组件去解析应用层协议,Processor 通过解析生成 Request 对象后,会调用 Adapter 的 Service 方法。
容器
Tomcat 设计了 4 种容器,分别是 Engine、Host、Context 和 Wrapper。这 4 种容器不是平行关系,而是父子关系。
Context 表示一个 Web 应用程序;Wrapper 表示一个 Servlet,一个 Web 应用程序中可能会有多个 Servlet;Host 代表的是一个虚拟主机,或者说一个站点,可以给 Tomcat 配置多个虚拟主机地址,而一个虚拟主机下可以部署多个 Web 应用程序;Engine 表示引擎,用来管理多个虚拟站点,一个 Service 最多只能有一个 Engine。
请求定位 Servlet 的过程:Tomcat 会创建一个 Service 组件和一个 Engine 容器组件,在 Engine 容器下创建两个 Host 子容器,在每个 Host 容器下创建两个 Context 子容器。由于一个 Web 应用通常有多个 Servlet,Tomcat 还会在每个 Context 容器里创建多个 Wrapper 子容器。
一个请求在 Tomcat 中流转的过程:
startup.sh 启动 tomcat 的过程:
Coyote
CyoOt是Tomcat的一个连接器组件,支持ajp、http1.1、spdy三种协议。
1、http
默认情况下,HTTP连接器使用Tomcat进行安装,并准备使用。该连接器具有最低的等待时间和最佳的整体性能。
对于集群,必须安装支持Web会话粘性的HTTP负载平衡器,以将流量引导到Tomcat服务器。Tomcat支持Adache HTTP Server 2 .x上的MODJOXER代理,并在默认情况下包含在Apache HTTP服务器2.2中作为负载均衡器。应该注意的是,HTTP代理的性能通常低于AJP的性能,所以AJP聚类通常是优选的。
2、ajp
当使用单个服务器时,在Tomcat实例前面使用 native webserver时的性能大部分时间都比具有默认HTTP连接器的独立Tomcat更差,即使Web应用程序的很大一部分是由静态文件构成的。如果出于任何原因需要与本机WebServer集成,AJP连接器将提供比代理HTTP更快的性能。从Tomcat的角度来看,AJP聚类是最有效的。它在功能上等同于HTTP集群。
Jasper
Tomcat的JSP引擎。解析JSP文件编译成java代码的servlet(可以处理卡特琳娜)。在运行时,Jasper检测到对JSP文件的更改并重新编译它们。
Pipeline和Value
对于应用服务器来说,增强各组件的扩展性以及灵活性是非常重要的,Tomcat采用职责链模式来实现每个Container组件处理请求的功能。
Pipeline代表职责链,后者表示阀门,具体的处理过程,每条线路上包含哪些操作,操作按照顺序一个个执行。Tomcat通过这种方式来决定每个容器的执行过程。
每一个容器都有一个 Pipeline 对象。
Tomcat监听客户端的请求,获得请求后交个各个组件去处理,返回响应数据到客户端,并且Tomcat能支持HTTP、AJP等协议。并且在扩展性、可用性上有着非常优秀的设计。
启动流程
tomcat的启动流程很标准化,入口是BootStrap,统一按照生命周期管理接口Lifecycle的定义进行启动。首先,调用init()方法逐级初始化,接着调用start()方法进行启动,同时,每次调用伴随着生命周期状态变更事件的触发。
请求流程
如果请求为:http://localhost:8080/index.jsp
- 请求被发送到本机端口8080,被在那里侦听的Coyote HTTP/1.1 Connector连接器组件获得
- Connector把该请求交给它所在的Service的Engine来处理,并等待Engine的回应
- Engine获得请求localhost:8080/index.jsp,匹配它所有虚拟主机Host
- Engine匹配到名为localhost的Host(即使匹配不到也把请求交给该Host处理,因为该Host被定义为该Engine的默认主机)
- localhost Host获得请求/index.jsp,匹配它所拥有的所有Context
- Host匹配到路径为/的Context,path=”/“的Context获得请求/index.jsp,在它的mapping table中寻找对应的servlet
- Context匹配到URL PATTERN为*.jsp的servlet,对应于JspServlet类
- 构造HttpServletRequest对象和HttpServletResponse对象,作为参数调用JspServlet的doGet或doPost方法
- Context把执行完了之后的HttpServletResponse对象返回给Host
- Host把HttpServletResponse对象返回给Engine
- Engine把HttpServletResponse对象返回给Connector
- Connector把HttpServletResponse对象返回给客户browser
类加载机制
tomcat自定义了三种类加载器。commonLoader、catalinaLoader、sharedLoader。
- commonLoader:Tomcat最基本的类加载器,加载路径中的class可以被Tomcat容器本身以及各个Webapp访问;
- catalinaLoader:Tomcat容器私有的类加载器,加载路径中的class对于Webapp不可见;
- sharedLoader:各个Webapp共享的类加载器,加载路径中的class对于所有Webapp可见,但是对于Tomcat容器不可见;
- WebappClassLoader:各个Webapp私有的类加载器,加载路径中的class只对当前Webapp可见;
jvm加载器加载机制是双亲委派模型,tomcat 为了实现隔离性,没有遵守这个约定,每个webappClassLoader加载自己的目录下的class文件,不会传递给父类加载器。
Tomcat8 和 Tomcat6比较大的区别是 :Tomcat8可以通过配置
总结
1 | Server:代表整个Servlet容器 |
以上的配置在Server.xml文件中