一、Tomcat的架构设计
1.Servlet规范
1.1 Servlet作用讲解
Servlet是JavaEE规范中的一种,主要是为了扩展Java作为Web服务的功能,统一定义了对应的接口,比如Servlet接口,HttpRequest接口,HttpResponse接口,Filter接口。然后由具体的服务厂商来实现这些接口功能,比如Tomcat,jetty等。
&ems;在规范里面并不会有具体的实现。可以自行看下源码,而在Servlet规范中规定了一个http请求到来的执行处理流程:对应的服务器容器会接收到对应的Http请求,然后解析该请求,然后创建对应的Servlet实例,调用对应init方法来完成初始化,把请求的相关信息封装为HttpServletRequest对象来调用Servlet的service方法来处理请求,然后通过HttpServletResponse封装响应的信息交给容器,响应给客户端。
1.2 Servlet核心API
我们再来回顾下Servlet中的核心API,这块对我们更好的掌握Tomcat的内容还是非常有帮助的。
API | 描述 |
ServletConfig | 获取servlet初始化参数和servletContext对象。 |
ServletContext | 在整个Web应用的动态资源之间共享数据。 |
ServletRequest | 封装Http请求信息,在请求时创建。 |
ServletResponse | 封装Http响应信息,在请求时创建。 |
ServletConfig:
容器在初始化servlet时,为该servlet创建一个servletConfig对象,并将这个对象通过init()方法来传递并保存在此Servlet对象中。核心作用:
- 获取初始化信息;
- 获取ServletContext对象。
ServletContext
一个项目只有一个ServletContext对象,可以在多个Servlet中来获取这个对象,使用它可以给多个Servlet传递数据,该对象在Tomcat启动时就创建,在Tomcat关闭时才会销毁!作用是在整个Web应用的动态资源之间共享数据。
在实际的Servlet开发中,我们会实现HttpServlet接口,在该接口中会实现GenericServlet,而在GenericServlet会实现ServiceConfig接口,从而可以获取ServletContext容器对象
所以在Servlet中我们可以很容易的获取到ServletContext对象,从而完成对应的操作。
public class ServletTwoImpl extends HttpServlet { @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html;charset=utf-8"); // 1、参数传递 ServletContext servletContext = this.getServletContext() ; String value = String.valueOf(servletContext.getAttribute("name")) ; System.out.println("value="+value); // 2、获取初始化参数 String userName= servletContext.getInitParameter("user-name") ; System.out.println("userName="+userName); // 3、获取应用信息 String servletContextName = servletContext.getServletContextName() ; System.out.println("servletContextName="+servletContextName); // 4、获取路径 String pathOne = servletContext.getRealPath("/") ; String pathTwo = servletContext.getRealPath("/WEB-INF/") ; System.out.println("pathOne="+pathOne+";pathTwo="+pathTwo); response.getWriter().print("执行:doGet; value:"+value); } } 复制代码
1.3 ServletRequest
HttpServletRequest接口继承ServletRequest接口,用于封装请求信息,该对象在用
户每次请求servlet时创建并传入servlet的service()方法,在该方法中,传入的servletRequest将会被强制转化为HttpservletRequest 对象来进行HTTP请求信息的处理。核心作用:
- 获取请求报文信息;
- 获取网络连接信息;
- 获取请求域属性信息。
1.4 ServletResponse
HttpServletResponse继承自ServletResponse,封装了Http响应信息。客户端每个请求,服务器都会创建一个response对象,并传入给Servlet.service()方法。核心作用:
- 设置响应头信息;
- 发送状态码;
- 设置响应正文;
- 重定向;
2.Tomcat的设计
通过上面Servlet规范的介绍,其实我们发下我们要实现Servlet规范的话,很重要的就得提供一个服务容器来获取请求,解析封装数据,并调用Servlet实例相关的方法。也就是如下图中的部分
这块的内容其实就是Tomcat,具体的我们来看看。
2.1 什么是Tomcat
Tomcat是一个容器,用于承载Servlet,那么我们说Tomcat就是一个实现了部分J2EE规范的服务器。J2 EE和Jakarta EE(Eclipse基金会)这两是啥?用于Tomcat10以后都是Jakarta EE,而9之前就是J2EE.
2.2 Tomcat的架构结构
我们通过上面的分析,知道Tomcat是一个Servlet规范的实现,要接收请求和响应请求,那么具体是如何实现的呢?这块我们可以通过conf下的server.xml得出对应的结论。
server.xml是Tomcat中最重要的配置文件,server.xml的每一个元素都对应了Tomcat中的一个组件 ;通过对xml文件中元素的配置,可以实现对Tomcat中各个组件的控制。因此,学习server.xml文件的配置,对于了解和使用Tomcat至关重要.
官方文档:tomcat.apache.org/tomcat-8.5-…
<?xml version="1.0" encoding="UTF-8"?> <Server port="8005" shutdown="SHUTDOWN"> <Service name="Catalina"> <Executor name="tomcatThreadPool" namePrefix="catalina-exec-" maxThreads="150" minSpareThreads="4"/> <Connector port="8080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" /> <Connector executor="tomcatThreadPool" port="8080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" /> <Engine name="Catalina" defaultHost="localhost"> <Realm className="org.apache.catalina.realm.LockOutRealm"> <!-- This Realm uses the UserDatabase configured in the global JNDI resources under the key "UserDatabase". Any edits that are performed against this UserDatabase are immediately available for use by the Realm. --> <Realm className="org.apache.catalina.realm.UserDatabaseRealm" resourceName="UserDatabase"/> </Realm> <Host name="localhost" appBase="webapps" unpackWARs="true" autoDeploy="true"> <Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs" prefix="localhost_access_log" suffix=".txt" pattern="%h %l %u %t "%r" %s %b" /> </Host> </Engine> </Service> </Server> 复制代码
极简模式
<Server> <Service> <Connector /> <Connector /> <Engine> <Host> <Context /><!-- 现在常常使用自动部署,不推荐配置Context元素,Context小节有详细说明 --> </Host> </Engine> </Service> </Server> 复制代码
梳理出的结构
对应的每个组件的作用。
2.3 组件分类
官网其实对上面的组件也做了分类:
顶级元素:
- Server:是整个配置文件的根元素
- Service:代表一个Engine元素以及一组与之相连的Connector元素
连接器:
- 代表了外部客户端发送请求到特定Service的接口;同时也是外部客户端从特定Service接收响应的接口。
容器:
容器的作用是处理Connector接收进来的请求,并产生对应的响应,Engine,Host和Context都是容器,他们不是平行关系,而是父子关系。
每个组件的作用:
- Engine:可以处理所有请求
- Host:可以处理发向一个特定虚拟主机的所有请求
- Context:可以处理一个特定Web应用的所有请求
核心组件的串联关系:
当客户端请求发送过来后其实是通过这些组件相互之间配合完成了对应的操作。
- Server元素在最顶层,代表整个Tomcat容器;一个Server元素中可以有一个或多个Service元素
- Service在Connector和Engine外面包了一层,把它们组装在一起,对外提供服务。一个Service可以包含多个Connector,但是只能包含一个Engine;Connector接收请求,Engine处理请求。
- Engine、Host和Context都是容器,且Engine包含Host,Host包含Context。每个Host组件代表Engine中的一个虚拟主机;每个Context组件代表在特定Host上运行的一个Web应用.
整体Tomcat的运行架构图