Tomcat的源码
- 一 . 理解Tomcat的架构
- 架构图
- 相关组件的介绍
- 二 Tomcat 启动源码分析
- Tomcat启动流程图
- Tomcat的启动流程
- 三. 相关组件说明
- 1. Startup.bat
- 2. catalina.bat
- 3 .Bootstrap
- 如何查看tomcat的Bootstrap类的源码 ?
- 主要组件说明
- 总结
- 4 Catalina
- 类结构图
- 主要组件说明
- 5 StandardServer
- 类结构图
- 主要组件说明
- 为什么启动Catalina 时 ,没有直接调用start的方法 ,而是使用反射来调用呢?
通过学习Tomcat的架构 . 相关源码以及运行原理 ,更加深刻的去了解和掌握Tomcat的使用
一 . 理解Tomcat的架构
架构图
相关组件的介绍
可以结合 Tomcat根目录下的conf目录下的server.xml来看
1. Server
Server 服务器的意思,代表整个tomcat 服务器,一个tomcat 只有一个Server Server 中包含至少一个Service 组件,用于提供具体服务。这个在配置文件中也得到很好的体现(port=“8005” shutdown="SHUTDOWN"是在8005 端口监听到"SHUTDOWN"命令,服务器就会停止)
2 .Service
Service 中的一个逻辑功能层, 一个Server 可以包含多个Service Service 接收客户端的请求,然后解析请求,完成相应的业务逻辑,然后把处理后的结果返回给客户端,一般会提供两个方法,一个start 打开服务Socket 连接,监听服务端口,一个stop 停止服务释放网络资源。
3 .Connector
称作连接器,是Service 的核心组件之一,一个Service 可以有多个Connector,主要是连接客户端请求,用于接受请求并将请求封装成Request 和Response,然后交给Container 进行处理,Container 处理完之后在交给Connector 返回给客户端。
4 .Container
Service 的另一个核心组件,按照层级有Engine,Host,Context,Wrapper 四种,一个Service 只有一个Engine,其主要作用是执行业务逻辑
5 .Engine
一个Service 中有多个Connector 和一个Engine,Engine 表示整个Servlet 引擎,一个Engine 下面可以包含一个或者多个Host,即一个Tomcat 实例可以配置多个虚拟主机,默认的情况下conf/server.xml 配置文件中
<Engine name="Catalina" defaultHost="localhost">
定义了一个名为Catalina 的Engine。一个Engine 包含多个Host 的设计,使得一个服务器实例可以承担多个域名的服务
6 .Host
代码语言:javascript复制代表一个站点,也可以叫虚拟主机,一个Host 可以配置多个Context,在server.xml 文件中的默认配置为
<Host name="localhost" appBase="webapps" unpackWARs="true"autoDeploy="true">
其中appBase=webapps, 也就是<CATALINA_HOME>webapps 目录,
unpackingWARS=true 属性指定在appBase 指定的目录中的war 包都自动的解压,
autoDeploy=true 属性指定对加入到appBase 目录的war 包进行自动的部署。
7 .Context
Context,代表一个应用程序,就是日常开发中的web 程序,或者一个WEB-INF 目录以及下面的web.xml 文件,换句话说每一个运行的webapp 最终都是以Context 的形式存在,每个Context 都有一个根路径和请求路径;与Host 的区别是Context 代表一个应用,如,默认配置下webapps 下的每个目录都是一个应用,其中ROOT 目录中存放主应用,其他目录存放别的子应用,而整个webapps 是一个站点。
二 Tomcat 启动源码分析
Tomcat启动流程图
Tomcat的启动流程
tomcat 的启动流程很标准化,入口是 BootStrap,统一按照生命周期管理接口 Lifecycle 的定义进行启动。 首先,调用 init()方法逐级初始化,接着调用 start()方法进行启动,同时, 每次调用伴随着生命周期状态变更事件的触发。
三. 相关组件说明
1. Startup.bat
查看bin目录下的Startup.bat Startup.bat的主要作用是启动与他在相同目录的catalina.bat ,并且无需指定启动参数(start)
2. catalina.bat
代码语言:javascript复制查看bin目录下的catalina.bat
set "CLASSPATH=%CLASSPATH%�TALINA_HOME%binbootstrap.jar"
set MAINCLASS=org.apache.catalina.startup.Bootstrap
set ACTION=start
总结 :
由上面摘抄的主要源码可知 ,在catalina.bat 启动时 ,主要是加载了一个叫bootstrap.jar 的jar包 . 在加载这个jar 以后 ,他又运行了这个 jar 下面的org.apache.catalina.startup.Bootstrap 这个类, 通过set ACTION=start
启动他的main方法 ,完成对Tomcat的启动
3 .Bootstrap
如何查看tomcat的Bootstrap类的源码 ?
- .通过maven仓库添加相应坐标 ,然后查看即可
- .不过现在提供一种最简单的方式 , 找到一个下载 一个任意版本的 tomcat
- 创建一个java项目 ,右击import ,选择file system 如下图 ,点击到tomcat对应的bin目录 ,finsh即可
- 导入完成后效果如下 :
- 根据 org.apache.catalina.startup.Bootstrap 这个绝对路径找到Bootstrap
- ctrl o 查看 ,该类的结构
主要组件说明
main 方法 是整个 tomcat 启动时的入口。在 main 方法中,使用 bootstrap.init()来初始化类加载器和创建 Catalina 实例,然后再启动 Catalina 线程
bootstrap.init()方法 用于初始化容器相关 ,首先创建类加载器, 然后通过反射创建 org.apache.catalina.startup.Catalina 实例。
总结
bootstrap的main方法首先会对类加载器 (classloader)进行初始化 ,然后调用load方法去初始化catalina ,然后catalina 去创建并初始化servler …直到最后初始化 Protocol handler .然后bootstrap再调用catalina 的start的方法 …依次类推,如下图
4 Catalina
类结构图
主要组件说明
Lifecycle 接口
Lifecycle 提供一种统一的管理对象生命周期的接口。通过 Lifecycle、LifecycleListener、LifecycleEvent,Catalina 实现了对 tomcat 各种组件、容器统一的启动和停止的方式。 在 Tomcat 服 务 开 启 过 程 中 启 动 的 一 些 列 组 件 、 容 器 , 都 实 现 了org.apache.catalina.Lifecycle 这个接口,其中的 init()、start() 方法、stop() 方法,为其子类实 现了统一的 start 和 stop 管理
load 方法解析 server.xml 配置文件
load 方法解析 server.xml 配置文件,并加载 Server、Service、Connector、Container、Engine、 Host、Context、Wrapper 一系列的容器。加载完成后,调用 initialize()来开启一个新的 Server
Digester 类解析 server.xml 文件
利用 Digester 类解析 server.xml 文件,得到容器的配置。
demon.start()
demon.start()方法会调用 Catalina 的 start 方法 Catalina 实例执行 start 方法。这里有两个点,一个是 load()加载 server.xml 配置、初始 化 Server 的过程,一个是 getServer().start()开启服务、初始化并开启一系列组件、子容器的 过程
5 StandardServer
类结构图
主要组件说明
service.initialize()
然后拿到 StandardServer 实例调用 initialize()方法初始化 Tomcat 容器的一系列组件。一 些容器初始化的的时候,都会调用其子容器的 initialize()方法,初始化它的子容器。顺序是 StandardServer、StandardService、StandardEngine、Connector。每个容器都在初始化自身相 关设置的同时,将子容器初始化。
为什么启动Catalina 时 ,没有直接调用start的方法 ,而是使用反射来调用呢?
代码语言:javascript复制 /**
* Start the Catalina daemon.
*/
public void start()
throws Exception {
if( catalinaDaemon==null ) init();
Method method = catalinaDaemon.getClass().getMethod("start", (Class [] )null);
method.invoke(catalinaDaemon, (Object [])null);
}
原因 : 因为Catalina 没有继承 LifeCycle这个接口 ,而LifeCycle规定了start ,stop等相关的方法 .所以他不能像StandardService 或StandardServer一样可以直接调用start 方法.