Tomcat源码分析
Posted 踩踩踩从踩
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Tomcat源码分析相关的知识,希望对你有一定的参考价值。
前言
本篇文章 会针对tomcat的实现原理,以及servlet Tomcat容器与运行机制,利用servlet的规范实现的一套web服务器,而spring mvc 也是 spring实现了servlet 的web应用程序。 tomcat这么流行 的Servlet Web容器,具有大量的配置可以扩展 良好的运行效果,在开发中不应该只是会用,更重要的是对原理以及实现方式的理解,也许最后你也能写出很好的一个tomcat框架,也是为什么去研究他的原因。
Tomcat介绍
Tomcat 实现了 Java Servlet , JavaServer Page , Java 表达式语言和 Java 的 WebSocket 技术的一个开源实 现。说白了就是一个非常流行的Servlet Web 容器。Apache Tomcat®软件是Jakarta Servlet,Jakarta Server Pages,Jakarta Expression Language,Jakarta WebSocket,Jakarta Annotations和Jakarta Authentication规范的开源实现。这些规范是 Jakarta EE 平台的一部分.
Jakarta EE 平台是 Java EE 平台的演变。Tomcat 10 及更高版本实现了作为 Jakarta EE 的一部分开发的规范。Tomcat 9 及更早版本实现了作为 Java EE 的一部分开发的规范。
在9.0.40 根据 不同的安装包去下载不同的安装包。
下载过后 的关键目录
1. lib Tomcat 依赖的 jar 包 2. logs catalina-xxx.log localhost-xxx.log 3. webapps web 应用部署目录, eclipse 中的配置演示在bin目录中 包括的 bat 文件启动的 对应的 win版本的启动以及 linux的启动方式。
我们要开发中间件 都参考这种形式去开发就可以了。
config目录 这里面 的web.xml 以及 catalina.policy 设置运行jvm的 权限 等参数 都放到 这里面。
在 policy 中 包括了 shutdown 以及 juc日志等。
配置文件 jconsol 调试参数,观察参数变化带来的影响 1. server.xml 调整连接池的大小 设置 I/O 模式 (BIO 与 NIO) 去掉 AJP 的 Connector 移除 access-log 日志 server 里面设置监听器等等。 以及 端口号 以及转发端口号执行器 线程池,重新定义 数量等等。
对应的默认 host 主机名称等 都在server.xml中配置。server.xml 中可以 设置的。 阈值 需要处理的事情。 区分多个应用 还是有个 上下文 context 上下文 在 context里面 最终进行映射 ,这里可以使用这个 作为访问 到 其他目录下面的 路径。 默认 是 root 访问到 工作目录下 ,然后可以根据配置 可以 访问到其他目录下面 其实这里是可以配置到 其他目录下面的 访问的。 包括 f盘或者其他的。 2. web.xml servlet 标签: DefaultServlet 、 JspServlet servlet-mapping 标签: servlet 的访问路径 mime-mapping 标签,支持的内容类型: json 、 xml 、 html 、 jpg 等
对于jsp 的请求访问 处理 方式等。
在 web.xml中可以 设置的json,能够解读 对应的映射地方 在 tomcat中 自动给我们设置好的。
tomcat-users.xml 配置相关的权限等。配置方式 在 文件上 都有一个例子给我们使用。
然后以及经常使用的地方也就是 webapps 启动 到 对应的 项目上
在使用上可以配置 对应 的访问地址,这都是tomcat提供给我们进行项目地址
jmx是jdk给我们提供的管理插件的功能,
部署方式
显式部署 1. 添加 context 元素方式 (server.xml)<Host appBase="webapps" autoDeploy="true" name="localhost" unpackWARs="true">
<Context path="/Demo1" docBase="d:/Demo1" reloadable="true"></Context>
</Host>
2.
创建
xml
的方式
在
conf/Catalina/localhost
目录创建的
xml
文件
<?xml version="1.0" encoding="UTF-8"?>
<Context docBase="d:/Demo1" reloadable="true"></Context>
能访问到其他目录下面。
隐式部署
将一个
war
文件或者整个应用程序复制到
Tomcat
的
webapps
Tomcat源码下载与构建
IDE 装载 Tomcat 项目源码 Apache Tomcat 9 (9.0.60) - Building Tomcat需要添加 环境变量这些。
Tomcat 体系结构 Apache Tomcat 9 Architecture (9.0.60) - Table of Contents Server 在 Tomcat 中, Server 代表整个容器。 Service 服务是一个中间组件,它在服务器内部,将一个或多个连接器连接到一个引擎。 Engine Engine 也就是以前版本中的 Container 。引擎表示特定服务的请求处理管道。 服务可能有多个连接器, 引擎接收并处理来自这些连接器的所有请求,将响应返回到适当的连接器以传输到客户端。 引擎接口可 以实现,以提供自定义引擎,尽管这是不常见的。引擎可以通过jvm 路由参数用于 Tomcat 服务器集群。 Engine 包含: Host 、 Context 、 Wrapper 这几个容器,他们都是 Container 子类型。 Connerctor Connector 负责把接收到的请求解析出来然后封装成 request 和 response 对象然后交给 Container 处理。 目前Connector 支持 http 和 ajp 协议。 连接器处理与客户端的通信。 Tomcat 有多个可用的连接器。 其中包括 HTTP 连接器、 AJP 连接器。当将 Tomcat作为独立服务器运行时使用 HTTP 协议的 HTTP 连接器;当将 Tomcat 连接到 Apache HTTPD 服务器等Web 服务器时使用的 AJP 协议的 AJP 连接器。 还可以创建自定义连接器。 Host 主机是网络名称的关联。 例如: www.yourcompany.com 能访问到 Tomcat 服务器。引擎可能包含多个主机,主机元素还支持网络别名,如yourcompany.com 和 abc.yourcompany.com 。 用户很少创建自定义主机,因为标准主机实现提供了重要的附加功能。 Host 说白了就是我们所理解的虚拟主机。 Context 上下文表示 Web 应用程序。 主机可能包含多个上下文,每个上下文具有唯一的路径。 上下文接口可以 实现创建自定义上下文,但这种情况很少,因为标准上下文提供了重要的附加功能。 Context 就是我们所部属的具体 Web 应用的上下文,每个请求都在是相应的上下文里处理的。 Wrapper Wrapper 是针对每个 Servlet 的 Container ,每个 Servlet 都有相应的 Wrapper 来管理。Tomcat容器与运行机制
Tomcat 启动步骤 Tomcat 的启动方式有下面几种方式: 1. 通过命令行启动 2. 通过 Java 程序,作为一个内嵌服务启动 3. 作为 windows 服务自动启动 bootstrap 作为启动类,赋值catlina.bat 调用格式, start参数, 其实 start.bat 调用时,都是调用的catalina.bat,这个可以在脚本中就可以看出来
这里对于主调用的 启动类就是 bootstrap在tomcat中 的启动类
对于参数来说, 传入的参数 第一个参数就是 start
启动 最终底层 都调用到了bootstarp
做了初始化的操作 init
继续 加载 catalina
紧接着 继续下去
根据不同的 命令 选择 不同的方式进行方式。
然后继续下去 就是 初始化 命名 ,
设置命名空间等等。 初始化的factroy
解析 对应的serverxml 并设置 home 的file
创建 摘要器等 初始化部分。
Bootstrap Tomcat 启动类, Tomcat 启动都是通过 org.apache.catalina.startup.Bootstrap 类的 main 方法来进行启 动的。它所做的工作包括:- 1. 启动类加载器
- 2. 加载启动类
- 3. Bootstrap的守护线程初始化方法执行完成
1. Catalina.setAwait(true)
2. Catalina.load()
- 1. initDirs()方法设置属性值,例如
catalina.home = D:/tomcat
catalina.base == catalina.home
- 2. initNaming初始化命名
setProperty ( javax . naming . Context . INITIAL_CONTEXT_FACTORY , org . apache . naming . java . javaURLContextFactory - > default )
- 3. createStartDigester()
- 4. 加载server.xml并解析
- 5. 日志输出处理
- 6. 调用所有的组件初始化方法,确保每个对象都注册到了JMX代理上
3. Catalina.start()
1. 启动NamingContext绑定所有JNDI引用到NamingContext中
2. 启动<Server>标签下的service
3. 通过Service启动StandardHost
- 配置ErrorReportValve以对不同的HTTP错误代码执行正确的HTML输出
- 启动管道中的阀门Valve(至少是ErrorReportValve)
- 配置StandardHostValve
- 启动HostConfig组件
4. Tomcat 在HTTP端口上开始接受请求
5. Servlet类调用
Tomcat处理请求的过程
- 1. 用户点击网页内容,请求被发送到本机端口8080,被在那里监听的Coyote HTTP/1.1 Connector获得。
- 2. Connector把该请求交给它所在的Service的Engine来处理,并等待Engine的回应。
- 3. Engine获得请求localhost/test/index.jsp,匹配所有的虚拟主机Host。
- 4. 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类。
- 5. 构造HttpServletRequest对象和HttpServletResponse对象,作为参数调用JspServlet的doGet() 或doPost().执行业务逻辑、数据存储等程序。
- 6. Context把执行完之后的HttpServletResponse对象返回给Host。
- 7. Host把HttpServletResponse对象返回给Engine。
- 8. Engine把HttpServletResponse对象返回Connector。
- 9. 1Connector把HttpServletResponse对象返回给客户Browser。
Tomcat中的组件
JVM 类加载器及双亲委派 JVM 类加载器结构public class Main
public static void main(String[] args)
Main main = new Main();
System.out.println(main.getClass().getClassLoader());
System.out.println(main.getClass().getClassLoader().getParent());
System.out.println(main.getClass().getClassLoader().getParent().getParent());
双亲委派机制
- 如果一个类加载器收到了类加载请求,它并不会自己先去加载,而是把这个请求委托给父类的加载器去执行。
- 如果父类加载器还存在其父类加载器,则进一步向上委托,依次递归,请求最终将到达顶层的启动类加载器。
- 如果父类加载器可以完成类加载任务,就成功返回,倘若父类加载器无法完成此加载任务,子加载器才会尝试自己去加载,这就是双亲委派模式。
双亲委派优势
- 避免重复加载
- 安全-防止核心API库被篡改
Catalina
Catalina 是 Tomcat 的核心组件,是 Servlet 容器, Catalina 包含了所有的容器组件,其他模块均为 Catalina 提供支撑。通过 Coyote 模块提供连接通信, Jasper 模块提供 JSP 引擎, Naming 提供 JNDI 服务,Juli提供日志服务。结构如下:主要的功能包括接收请求,处理请求,返回结果,这些具体的实现是在catalina里面的子容器里面。
Lifecycle
Tomcat 的卡特琳娜( Catalina )由许多组件构成。当 Catalina 启动的时候,这些组件也要跟着一起启动,并且当Catalina 关闭的时候,这些组件也要同时关闭,并且要进行必要的清理操作,释放资源。例如,当容器关闭的时候,需要调用已加载的servlet 对象的 destroy 方法, session 对象也要持久化到secondary storage(二级存储,通常指的就是硬盘)。这就要求所有 Component 有一致的方法,可以统一处理。
以上是关于Tomcat源码分析的主要内容,如果未能解决你的问题,请参考以下文章