Tomcat
https://blog.csdn.net/weixin_48321993/article/details/125422511
https://blog.csdn.net/weixin_48321993/article/details/126027770
Web容器基础认知
如何实现服务器和浏览器的交互
客户端和服务器端之间的交互式通过Socket来实现的,它属于应用层的协议。
- HTTP协议
- Socket
Socket是网络连接的一个端点。套接字使得一个应用可以从网络中读取和写入数据。
放在两个不同计算机上的两个应用可以通过连接发送和接受字节流。为了从你的应用发送一条信息到另一个应用,你需要知道另一个应用的 IP 地址和套接字端口。
在 Java 里边,套接字指的是java.net.Socket类。 - ServerSocket
Socket 类代表一个客户端套接字,即任何时候你想连接到一个远程服务器应用的时候你构造的套接字。
现在,假如你想实施一个服务器应用,例如一个 HTTP 服务器或者 FTP 服务器,你需要一种不同的做法。这是因为你的服务器必须随时待命,因为它不知道一个客户端应用什么时候会尝试去连接它。
为了让你的应用能随时待命,你需要使用java.net.ServerSocket类。这是服务器套接字的实现。
ServerSocket 和 Socket 不同,服务器套接字的角色是等待来自客户端的连接请求。一旦服务器套接字获得一个连接请求,它创建一个 Socket 实例来与客户端进行通信。
什么是Servlet
所谓Servlet,其实就是Sun为了让Java能实现动态可交互的网页,从而进入Web编程领域而制定的一套标准!
一个Servlet主要做下面三件事情:
- 创建并填充Request对象,包括:URI、参数、method、请求头信息、请求体信息等
- 创建Response对象
- 执行业务逻辑,将结果通过Response的输出流输出到客户端
Servlet没有main方法,所以,如果要执行,则需要在一个容器里面才能执行,这个容器就是为了支持Servlet的功能而存在。
Tomcat其实就是一个Servlet容器的实现。
Tomcat和Spring、Spring MVC的关系
Spring MVC
DispatcherServlet
在整个 Spring MVC 框架中,DispatcherServlet 处于核心位置,它负责协调和组织不同组件完成请求处理并返回响应工作。
DispatcherServlet 是 SpringMVC统一的入口,所有的请求都通过它。
总结
- Tomcat是HTTP服务器和Servlet容器,负责给类似Spring这种servlet提供一个运行的环境。
- Http服务器,可以把HTTP服务器想象成前台的接待,负责网络通信和解析请求;
- Servlet容器是业务部门,负责处理业务请求。
- Tomcat作为Web服务器和Servlet容器的结合,可以接受网络http请求解析为Servlet规范的请求对象和响应对象。
- Servlet是规范。
- HttpServletRequest对象是Tomcat提供的,Tomcat是实现规范的Servlet容器。
- SpringMVC是处理Servlet请求的应用,其中DispatcherServlet实现了Servlet接口,Tomcat负责加载和调用DispatcherServlet。
- DispatcherServlet有自己的容器-Spring MVC容器(子容器),这个容器负责管理Spring MVC相关的bean,比如Controler和ViewResolver等。同时,Spring中还有其他的Bean,比如Service和DAO等,这些由全局的Spring IOC容器(父容器)管理。
- 如果只是使用spring(不包含springmvc),那么是tomcat容器解析xml文件,通过反射实例化对应的类,根据这些servlet规范实现类,触发对应的代码处理逻辑,这个时候tomcat负责http报文的解析和servlet调度的工作。
- 如果使用spring mvc,那么tomcat只是解析http报文,然后将其转发给dispatchsetvlet,然后由springmvc根据其配置,实例对应的类,执行对应的逻辑,然后返回结果给dispatchservlet,最后由它转发给tomcat,由tomcat负责构建http报文数据。
Tomcat源码结构
Tomcat 源码位于 java
文件夹下面。java
目录下,分为了两个结构,一个是javax
,一个是org.apache
。
javax
在javax
中保存的是新的JavaEE规范。可以具体来看看每个目录的作用。
模块 | 作用说明 |
---|---|
annotation | annotation 这个模块的作用是定义了一些公用的注解,避免在不同的规范中定义相同的注解。 |
ejb | ejb是个古老的传说,我们不管 |
el | 在jsp中可以使用EL表达式,这么模块解析EL表达式的 |
和邮件相关的规范 | |
persistence | 持久化相关的 |
security | 和安全相关的内容 |
servlet | 这个指定的是Servlet的开发规范,Tomcat本质上就是一个实现了Servlet规范的一个容器,Servlet定义了服务端处理Http请求和响应的方式(规范) |
websocket | 定义了使用 websocket 协议的服务端和客户端 API |
xml.ws | 定义了基于 SOAP 协议的 xml 方式的 web 服务 |
org.apache
org.apache
这个包是Tomcat的源码包,也是针对上面的JavaEE规范的部分实现,Tomcat的本质就是对JavaEE的某些规范的实现合集,首先肯定实现了Servlet规范。
模块 | 作用 |
---|---|
catalina | catalina是Tomcat的核心模块,里面完整的实现了Servlet规范,Tomcat启动的主方法也在里面,后面我们分析的重点。 |
coyote | tomcat 的核心代码,负责将网络请求转化后和 Catalina 进行通信。 |
el | 这个是上面javax中的el规范的实现 |
jasper | 主要负责把jsp代码转换为java代码。 |
juli | 日志相关的工具 |
naming | 命名空间相关的内容 |
tomcat | 各种辅助工具,包括 websocket 的实现。 |
Tomcat架构设计
Tomcat的前身为Catalina,Catalina又是一个轻量级的Servlet容器
在美国,catalina是一个很美的小岛。所以Tomcat作者的寓意可能是想把Tomcat设计成一个优雅美丽且轻量级的web服务器。
Tomcat从4.x版本开始除了作为支持Servlet的容器外,额外加入了很多的功能,比如:jsp、el、naming等等,所以说Tomcat不仅仅是Catalina。
从组件的角度看
Tomcat 要实现 2 个核心功能:
- 处理 Socket 连接,负责网络字节流与 Request 和 Response 对象的转化。
- 加载和管理 Servlet,以及具体处理 Request 请求。
因此 Tomcat 设计了两个核心组件连接器(Connector)和容器(Container)来分别做这两件事情。连接器负责对外交流,容器负责内部处理。
Connector 连接器和Container 容器可以说是 Tomcat 架构里最重要的两部分。
Server
表示整个tomcat服务器,它提供了一种优雅的方式来启动和停止整个系统,不必单独启停连接器和容器。
它是Tomcat构成的顶级构成元素,所有一切均包含在Server中,包含多组服务(Service),负责管理和启动各个Service。Service
表示服务,Server可以运行多个Service服务。比如一个Tomcat里面可运行订单服务、支付服务、用户服务等等;Server的实现类StandardServer可以包含一个到多个Services,Service的实现类为StandardService调用了容器(Container)接口,其实是调用了Servlet Engine(引擎),而且StandardService类中也指明了该Service归属的Server。
- 核心组件:Connector 连接器
表示连接器, 它将Service和Container连接起来。
注册在Service中,指定当前Service要监听的端口port。
用于监听端口,接受来自客户端的请求,并将请求转交给Engine处理,同时将来自Engine的答复返回给客户端。- ProtocolHandler
- Endpoint
- Processor
- Adapter
- 核心组件:Container 容器
表示容器,可以看做Servlet容器。
引擎(Engine)、主机(Host)、上下文(Context)和Wraper均继承自Container接口,所以它们都是容器。- Engine 引擎
引擎是Servlet 的顶层容器,用来管理多个虚拟站点,一个 Service 最多只能有一个 Engine。 - Host 虚拟主机
虚拟主机,负责 web 应用的部署和 Context 的创建。可以给 Tomcat 配置多个虚拟主机地址,而一个虚拟主机下可以部署多个 Web 应用程序。 - Context 上下文
Web 应用上下文,包含多个 Wrapper,负责 web 配置的解析、管理所有的 Web 资源。一个Context对应一个 Web 应用程序。 - Wrapper 包装器
表示一个 Servlet,最底层的容器,是对 Servlet 的封装,负责 Servlet 实例的创建、执行和销毁。
- Engine 引擎
- Service其他内部组件
Manager – 管理器,用于管理会话Session
Logger – 日志器,用于管理日志
Loader – 加载器,和类加载有关,只会开放给Context所使用
Pipeline – 管道组件,配合Valve实现过滤器功能
Valve – 阀门组件,配合Pipeline实现过滤器功能
Realm – 认证授权组件
- 核心组件:Connector 连接器
web.xml
从一个完整请求的角度看
假设来自客户的请求为:http://localhost:8080/test/index.jsp
- 请求被发送到本机端口8080,被在那里侦听的Coyote HTTP/1.1 Connector获得
- Connector把该请求交给它所在的Service的Engine来处理,并等待Engine的回应
- Engine获得请求localhost:8080/test/index.jsp,匹配它所有虚拟主机Host
- Engine匹配到名为localhost的Host(即使匹配不到也把请求交给该Host处理,因为该Host被定义为该Engine的默认主机)
- localhost Host获得请求/test/index.jsp,匹配它所拥有的所有Context
- Host匹配到路径为/test的Context(如果匹配不到就把该请求交给路径名为””的Context去处理)
- path=”/test”的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
简而言之,Connector 连接器接收连接请求,创建Request和Response对象用于和请求端交换数据,然后分配线程让Engine(也就是Servlet容器)来处理这个请求,并把产生的Request和Response对象传给Engine。当Engine处理完请求后,通过Connector将响应返回给客户端。
Tomcat如何接收到一个http请求
Connector组件的Endpoint中的Acceptor监听客户端套接字连接并接收Socket。
深入了解:Tomcat生命周期
为了统一管理Tomcat
中的核心组件的生命周期,专门设计了LifeCycle
接口来统一管理。
LifeCycle接口设计
深入了解:Tomcat初始化与启动
startup.bat -> catalina.bat 中 找到启动的主类为 org.apache.catalina.startup.Bootstrap
深入了解:核心组件Connector
深入了解:核心组件Container
Container是容器的父接口,所有子容器都必须实现这个接口,简单来说就是服务器部署的项目是运行在Container中的。
Container里面的Servlet获取到Connector传递过来对应的的Request对象和Response对象进行相应的操作。
Mapper组件机制及请求处理机制
https://blog.csdn.net/NaShiYu/article/details/111773908
Tomcat 类加载机制
打破双亲委派
为什么Tomcat的类加载器不是双亲委派模型
Java默认的类加载机制是通过双亲委派模型来实现的,而Tomcat实现的方式又和双亲委派模型有所区别。
原因在于一个Tomcat容器允许同时运行多个Web程序,每个Web程序依赖的类又必须是相互隔离的。
因此,如果Tomcat使用双亲委派模式来加载类的话,将导致Web程序依赖的类变为共享的。
举个例子,假如我们有两个Web程序,一个依赖A库的1.0版本,另一个依赖A库的2.0版本,他们都使用了类xxx.xx.Clazz,其实现的逻辑因类库版本的不同而结构完全不同。那么这两个Web程序的其中一个必然因为加载的Clazz不是所使用的Clazz而出现问题!而这对于开发来说是非常致命的!
- Common类加载器,负责加载Tomcat和Web应用都复用的类
- Catalina类加载器,负责加载Tomcat专用的类,而这些被加载的类在Web应用中将不可见
- Shared类加载器,负责加载Tomcat下所有的Web应用程序都复用的类,而这些被加载的类在Tomcat中将不可见
- WebApp类加载器,负责加载具体的某个Web应用程序所使用到的类,而这些被加载的类在Tomcat和其他的Web应用程序都将不可见
- Jsp类加载器,每个jsp页面一个类加载器,不同的jsp页面有不同的类加载器,方便实现jsp页面的热插拔