tomcat学习随笔

Tomcat结构与原理

  • 一、组成
    • Server
      • Service
        • Connector
          • ProtocolHandler
            • Endpoint
            • Processor
          • Adaptor
        • Container
          • Engine
          • Host
          • Context
          • Wrapper
  • 运行
  • 热部署
    • jsp
    • war

tomcat学习随笔_第1张图片

tomcat根路径目录结构示意图

一、组成

tomcat学习随笔_第2张图片

tomcat结构debug示意图

Server

tomcat的实例,支持多个Service

Service

web服务,主要包含Connector(多个)和Container(一个)

Connector

连接器(支持多个)作用是协议(如http)通信,负责监听端口来接收消息请求,并传递给Container进行业务处理,再将结果响应会客户端。
过程:网络通信- 应用层协议解析-Request/Response与ServeletRequest/ServeletResponse转化

属性 含义
protocol 监听的协议,默认是HTTP/1.1(7.0:org.apache.coyote.http11.Http11Protocol,8.0:org.apache.coyote.http11.Http11NioProtocol)
port 监听的端口号
minThread 服务器启动时创建的处理请求的线程数
maxThread 最大可以创建的处理请求的线程数
enableLookups 为true表示可以通过调用request.getRemoteHost()进行DNS查询来得到远程客户端的实际主机名;否则不进行DNS查询,而是返回其ip地址
acceptCount 当所有可以使用的处理请求的线程数都被使用时,可以放到处理队列中的请求数,超过这个数的请求将不予处理
connectionTimeout 超时的时间数(以毫秒为单位)
redirectPort 当前Connector不支持SSL,收到了一个SSL传输请求时重定向的端口号
SSLEnabled 是否开启 sll 验证,在Https 访问时需要开启
URIEncoding URL字符编码

更多见源码:org.apache.catalina.connector.Connector

ProtocolHandler

协议处理器,将不同协议和通信方式组合封装。本身就是顶层接口。
举例过程:org.apache.coyote.http11.Http11NioProtocol --> org.apache.tomcat.util.net.AbstractEndpoint(start --> startAcceptorThreads) --> org.apache.coyote.AbstractProtocol

Endpoint

端点,负责socket的接收和发送。顶层抽象类是org.apache.tomcat.util.net.AbstractEndpoint。

Acceptor
AbstractEndpoint子类的内部类,继承AbstractEndpoint的抽象内部类Acceptor,具体逻辑实现不同。
作用就是用于监听 Socket 连接请求。

Handler
AbstractEndpoint子类的内部类,继承AbstractEndpoint的内部接口Handler,供具体ProtocolHandler的内部类包装。
作用就是与Processor交互。

SocketProcessor
AbstractEndpoint子类的内部类,实现Runnable,具体逻辑实现不同。
作用就是通过run方法执行handler与Processor交互。

Processor

处理器,负责构建(填充数据)Request和Response对象

Adaptor

适配器,负责Request/Response与ServeletRequest/ServeletResponse转化。
如org.apache.catalina.connector.CoyoteAdapter

Container

一个Service中仅有一个,负责业务处理。包含Engine、Host、Context、Wrapper
tomcat学习随笔_第3张图片

tomcat container子类结构示意图
Engine

引擎,用于处理连接的执行器。一个Service只能配置一个Engine

属性 含义
name 名称
defaultHost 默认的Host虚拟机域名,如localhost

更多见源码:org.apache.catalina.core.StandardEngine

Host

虚拟机,基于域名匹配至指定虚拟机,类似于nginx 当中的server

属性 含义
name 域名,必须配置,如localhost,至少有一个Host的name与Engine的defaultHost一致
appBase 应用的根路径,支持相对路径(相对于tomcat安装目录根目录),默认webapps
unpackWARs 是否自动解压war,默认true
autoDeploy 是否热部署war:替换到整个Context环境(即包含session之类),默认true

更多见源码:org.apache.catalina.core.StandardHost

Context

应用上下文,隔离各个web应用,一个Context对应一个WebappClassLoader。一个Host下支持配置多个Context

属性 含义
docBase 应用物理路径,支持相对路径(相对于Host的appBase),默认不配置
path 应用上下文路径,默认不配置
reloadable 是否热加载class:替换掉WebappClassLoader。正式环境不用,默认false

更多见源码:org.apache.catalina.core.StandardContext

Wrapper
Pipeline结构
org.apache.catalina.core.ContainerBase
	org.apache.catalina.core.StandardPipeline

源码过程
org.apache.tomcat.util.net.AprEndpoint.SocketProcessor#doRun
org.apache.coyote.AbstractProtocol.AbstractConnectionHandler#process
org.apache.coyote.http11.AbstractHttp11Processor#process
// this.adapter.service(this.request, this.response);
	org.apache.catalina.connector.CoyoteAdapter#service
	// this.connector.getService().getContainer().getPipeline().getFirst().invoke(request, response);
		org.apache.catalina.core.StandardEngineValve#invoke
		// host.getPipeline().getFirst().invoke(request, response);
			org.apache.catalina.core.StandardContextValve#invoke
			// wrapper.getPipeline().getFirst().invoke(request, response);
				org.apache.catalina.core.StandardWrapperValve#invoke
				// filterChain.doFilter(request.getRequest(), response.getResponse());
					org.apache.catalina.core.ApplicationFilterChain#internalDoFilter
					// this.servlet.service(request, response);
简易流程
EngineValue --> HostValue --> ContextValue --> WrapperValue --> FilterChain --> Servelet

运行

org.apache.catalina.startup.Bootstrap#main

1、初始化
org.apache.catalina.startup.Bootstrap#load
org.apache.catalina.startup.Catalina#load

1.1、加载配置初始化
org.apache.tomcat.util.digester.Digester#parse
com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl#scanDocument
com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl#scanStartElement
com.sun.org.apache.xerces.internal.parsers.AbstractXMLDocumentParser#emptyElement
org.apache.tomcat.util.digester.Digester#startElement
调用各种rule
org.apache.tomcat.util.digester.ObjectCreateRule#begin

realClassName
	org.apache.catalina.core.StandardServer
	org.apache.catalina.core.StandardService
	org.apache.catalina.core.StandardEngine
	org.apache.catalina.core.StandardHost

org.apache.catalina.startup.ConnectorCreateRule#begin

org.apache.catalina.connector.Connector
	# HTTP/1.1。其他协(见org.apache.catalina.connector.Connector#setProtocol)类似
	org.apache.coyote.http11.Http11AprProtocol
		org.apache.tomcat.util.net.AprEndpoint
		org.apache.coyote.http11.Http11AprProtocol.Http11ConnectionHandler(包装Processor

1.2、init方法初始化
org.apache.catalina.core.StandardServer#initInternal
org.apache.catalina.core.StandardService#initInternal
org.apache.catalina.core.StandardEngine#initInternal
org.apache.catalina.connector.Connector#initInternal
org.apache.catalina.mbeans.MBeanFactory#createStandardContext

创建org.apache.catalina.connector.CoyoteAdapter并设置到org.apache.coyote.ProtocolHandler(如org.apache.coyote.http11.Http11AprProtocol|--> org.apache.coyote.AbstractProtocol#init
	|--> org.apache.tomcat.util.net.AbstractEndpoint#init
 		|--> org.apache.tomcat.util.net.AbstractEndpoint#bind(有具体实现类实现,目的就是创建如socket的通信)

2、启动
org.apache.catalina.startup.Bootstrap#start
org.apache.catalina.startup.Catalina#start
org.apache.catalina.core.StandardServer#startInternal
org.apache.catalina.core.StandardService#startInternal
org.apache.catalina.core.StandardEngine#startInternal
org.apache.catalina.connector.Connector#startInternal

|--> org.apache.coyote.AbstractProtocol#start
	|--> org.apache.tomcat.util.net.AbstractEndpoint#start
		|--> 相应的Endpoint实现类的内部Poller类#init + start

tomcat类加载器
tomcat学习随笔_第4张图片

tomcat类加载器debug示意图

tomcat学习随笔_第5张图片

tomcat破坏双亲委派debug示意图

热部署

jsp

替换JasperLoader,重新加载类

org.apache.jasper.servlet.JspServletWrapper#service
// this.ctxt.compile();
	// 判断是否做修改,修改则重新生成java和class文件,并设置jspLoader加载器为null,reload标志为true
	org.apache.jasper.JspCompilationContext#compile
	// this.jspLoader = null;
	// this.jspCompiler.compile();
	// this.jsw.setReload(true);
		org.apache.jasper.compiler.Compiler#compile
			org.apache.jasper.compiler.JDTCompiler#generateClass
// servlet = this.getServlet();
	// 如果reload为true,则销毁旧servelet对象(是否卸载相关类取决于GC能够回收)、生成新的对象以及初始化
	org.apache.jasper.servlet.JspServletWrapper#getServlet
	// this.destroy();
	// servlet = (Servlet)instanceManager.newInstance(this.ctxt.getFQCN(), this.ctxt.getJspLoader());
	// servlet.init(this.config);

替换org.apache.catalina.loader.WebappClassLoader,重新加载类
热加载class

org.apache.catalina.core.ContainerBase#backgroundProcess
// loader.backgroundProcess();
	org.apache.catalina.loader.WebappLoader#backgroundProcess
	// this.reloadable && this.modified() 为true就就行reload,其中this.modified() 是遍历了当前应用所有资源是否更改
		org.apache.catalina.core.StandardContext#reload
		// this.stop();
		// this.start();

war

重新初始化Context上下文环境,就是重新启动一个应用(断点过程一直无法执行到)。
代码调试过程,修改war展开后的应用根目录,虽然会被监听到,但因为是目录跳过了后续流程(没有reload、deployed或host存在该应用名称的缓存),相当于不处理(除非删除应用根目录之后再添加) 对war包更新、新增 和 应用移除(war包展开目录)有效
热部署war

org.apache.catalina.core.ContainerBase.ContainerBackgroundProcessor#processChildren
	org.apache.catalina.core.StandardContext#backgroundProcess
		org.apache.catalina.core.ContainerBase#backgroundProcess
			org.apache.catalina.util.LifecycleSupport#fireLifecycleEvent
			// 通过listener来通知
				org.apache.catalina.startup.HostConfig#lifecycleEvent
				// this.check();
					// 判断资源是否更改,更改则同样执行org.apache.catalina.core.StandardContext#reload
					org.apache.catalina.startup.HostConfig#checkResources
					// 条件符合情况下,重新初始化context
					org.apache.catalina.startup.HostConfig#deployApps()
						org.apache.catalina.startup.HostConfig#deployDescriptor

参考 tomcat9调优3:Tomcat类加载机制及其热部署热加载原理剖析

你可能感兴趣的:(笔记,容器,服务器,tomcat,java)