Introduction
Apache Tomcat软件是Java Servlet、JavaServer Pages、Java Expression Language和Java WebSocket技术的一个开源实现。Java Servlet、JavaServer Pages、Java Expression Language和Java WebSocket规范是在Java Community Process下开发的。
简单来说,Tomcat可以看成是Web服务器加Servlet容器。
在上面的流程图中,Tomcat通过Connector组件接收并解析HTTP请求,将ServletRequest对象发送给Container进行处理。Container处理完成后会将响应封装成ServletRespone对象返回给Connector,然后Connector再将ServletRespone对象解析成HTTP响应文本格式发送给客户端,至此Tomcat就完成了一次网络通信。
Architecture
在Tomcat架构图中主要包含三个组件:Service、Connectot、Container。
- Server:Web服务器,一个Server中可以包含多个Service。
- Service:每一个Service都是独立的,它们共享一个JVM以及系统类库,并且一个Service负责维护多个Connector和一个Container。
- Connector:Connector用于连接Service和Container,解析客户端的请求并转发到Container,以及转发来自Container的响应。每一种不同的Connector都可以处理不同的请求协议,包括HTTP/1.1、HTTP/2、AJP等等。
- Container:Tomcat的Container包含四种子容器,分别为Engine、Host、Context和Wrapper。其中,一个Container对应一个Engine,一个Engine可以包含多个Host,一个Host可以包含多个Context,一个Context又包含多个Wrapper。
- Engine:可以看成是容器对外提供功能的入口,每个Engine是Host的集合,用于管理各个Host。
- Host:可以看成一个虚拟主机,一个Tomcat可以支持多个虚拟主机。虚拟主机的作用就是运行多个应用,它负责安装和展开这些应用,并且标识这个应用以便能够区分它们,每个虚拟主机对应的一个域名,不同Host容器接受处理对应不同域名的请求。
- Context:上下文容器,可以将其看成一个Web应用,每个Host里面可以运行多个Web应用。同一个Host里面不同的Context,其contextPath必须不同,默认Context的contextPath为空格或斜杠。
- Wrapper:对Servlet的抽象和包装,每个Context可以有多个Wrapper,用于支持不同的Servlet,每个Wrapper实例表示一个具体的Servlet定义,Wrapper主要负责管理Servlet,包括Servlet的装载、初始化、执行以及资源回收。
下图展示了请求在Container中的解析过程:
Three Major Components
Java Web中有三大组件,分别是Servlet、Filter和Listener。三者的加载顺序为Listener->Filter->Servlet。
在org.apache.catalina.core.StandardContext类的startInternal方法中,首先调用了listenerStart,接着是filterStart,最后是loadOnStartup。这三处调用分别触发了Listener、Filter、Servlet的构造加载。
Listener
Conception
Listener是一个实现了特定接口的Java程序,用于监听一个方法或者属性,当被监听的方法被调用或者属性改变时,就会自动执行某个方法。
与Listener相关的概念:
- 事件:某个方法被调用,或者属性的改变;
- 事件源:被监听的对象(如ServletContext、requset、方法等);
- 监听器:用于监听事件源,当发生事件时会触发监听器。
监听器分类:
事件源 | 监听器 | 描述 |
---|---|---|
ServletContext | ServletContextListener | 用于监听 ServletContext 对象的创建与销毁过程 |
HttpSession | HttpSessionListener | 用于监听 HttpSession 对象的创建和销毁过程 |
ServletRequest | ServletRequestListener | 用于监听 ServletRequest 对象的创建和销毁过程 |
ServletContext | ServletContextAttributeListener | 用于监听 ServletContext 对象的属性新增、移除和替换 |
HttpSession | HttpSessionAttributeListener | 用于监听 HttpSession 对象的属性新增、移除和替换 |
ServletRequest | ServletRequestAttributeListener | 用于监听 HttpServletRequest 对象的属性新增、移除和替换 |
HttpSession | HttpSessionBindingListener | 用于监听 JavaBean 对象绑定到 HttpSession 对象和从 HttpSession 对象解绑的事件 |
HttpSession | HttpSessionActivationListener | 用于监听 HttpSession 中对象活化和钝化的过程 |
按照监听的对象不同将其划分为三类:ServletContextListener,HttpSessionListener和ServletRequestListener。
Usage
- ServletContextListener配置
1 | package com.memoryshell.tomcatmemoryshell; |
- web.xml配置
1 |
|
Filter
Conception
Filter用于拦截用户请求以及服务端的响应,能够在拦截之后对请求和响应做出相应的修改。Filter不是Servlet,不能直接访问,它能够对于Web应用中的资源(Servlet、JSP、静态页面等)做出拦截,从而实现一些相应的功能。
Life Cycle
Filter的生命周期分为三个阶段:
- 初始化阶段:Filter的初始化阶段只会在Web应用程序启动时调用一次。
- 拦截和过滤阶段:当客户请求访问与过滤器关联的URL的时候,Servlet过滤器将先执行doFilter方法。FilterChain参数用于访问后续过滤器。
- 销毁阶段:Filter的销毁阶段只会在web应用移除或服务器停止时才调用一次来卸载Filter对象。
Usage
- FilterChain
一个Servlet可以注册多个Filter,Web容器会将注册的多个Filter组合成一个”Filter链”,并按照一定的顺序依次执行各Filter的doFilter方法。
- Filter execution sequence
由于Filter的注册方式不同,其执行顺序也有所不同。
- 基于注解配置:按照类名的字符串比较规则比较,值小的先执行;
- 使用web.xml配置:根据对应的Mapping的顺序组织,谁定义在上边谁就在前。
- FilterConfig
和Servlet类似,由于Filter也有可能访问Servlet,所以Servlet规范将代表ServletContext对象和Filter的配置参数信息都封装到一个称为FilterConfig的对象中。
FilterConfig接口则用于定义FilterConfig对象应该对外提供的方法,以便在Filter的doFilter方法中可以调用这些方法来获取ServletContext对象,以及获取在web.xml文件中的一些初始化参数。
Servlet
Conception
Servlet是运行在Web服务器或应用服务器上的程序,它是作为来自HTTP客户端的请求和HTTP服务器上的数据库或应用程序之间的中间层。用来处理客户端请求的动态资源,并根据请求生成相应的返回信息提供给用户,当Tomcat接收到来自客户端的请求时,会将其解析成RequestServlet对象并发送到对应的Servlet上进行处理。
Life Cycle
Servlet的生命周期分为五个阶段:
- 加载阶段:当Tomcat第一次访问Servlet时,会创建Servlet的实例。
- 初始化阶段:当Servlet实例化后,Tomcat会调用init方法初始化这个对象。
- 处理服务阶段:当浏览器访问Servlet时,Servlet会调用service方法处理请求。
- 销毁阶段:当Tomcat关闭时或者检测到Servlet要从Tomcat删除时,会自动调用destroy方法,让该实例释放掉所占的资源。除此之外,一个Servlet如果长时间不被使用的话,也会被Tomcat自动销毁。
- 卸载阶段:当Servlet调用完destroy方法后,会等待垃圾回收。如果有需要再次使用这个Servlet时,会重新调用init方法进行初始化操作。
Usage
根据上文对Servlet生命周期的了解,当需要实现一个Servlet时,需要继承Servlet接口,并实现相应的五个方法。
在Tomcat中已经封装好了两个类,分别是GenericServlet类和HttpServlet类。GenericServlet抽象类实现了Servlet接口,并对Servlet接口中除service方法外的其它四个方法进行了简单实现。
通过继承GenericServlet类创建来Servlet,只需要重写service方法即可。但是,GenericServlet抽象类是一个通用的Servlet类,并不是针对某种应用场景而设计的,因此在处理HTTP请求的时候需要手动实现对HTTP请求的解析和封装。
HttpServlet是GenericServlet的子类,它在GenericServlet的基础上专门针对HTTP协议进行了处理。其针对每一种HTTP请求都设置了一种处理方法。当使用HttpServlet类的时候,只需要根据HTTP请求类型重写相应的处理方法即可。
1 |
|