深入分析理解Tomcat体系结构
Tomcat整体结构
由上图可知Tomcat的顶层容器是Server,而且一个Tomcat对应一个Server,一个server有多个service提供服务.service包含两个重要组件:Connector和Container.这个后面详细讲解.这个Server由谁来管理呢?当然是Catalina了,她是tomcat的管理类,她的三个方法load,start,stop分别用来管理整个服务器的生命周期.
Load方法:Load方法根据conf/server.xml文件创建Server并调用Server的init方法进行初始化.Server的init方法调用所有service的init方法,service的init方法调用所有Connector和Container的init方法.整个初始化工作就完成了.
Start方法:用于启动服务,类似init,也是逐层进行启动.
Stop方法:用于关闭服务,类似init,也是逐层调用关闭.
最后,CatAlina中的await方法非常重要,这个方法调用Server中的await方法,这个方法的作用就是进入一个循环,保持主线程不退出.
Tomcat组件启动过程
Bootstrap的启动过程
Tomcat启动的入口方法就是Bootstrap中的main方法,代码如下:
public static void main(String args[]) {
if (daemon == null) {
// Don't set daemon until init() has completed
Bootstrap bootstrap = new Bootstrap();
try {//初始化ClassLoader,创建了Catalina实例,赋值给catalinaDaemon
bootstrap.init();
} catch (Throwable t) {
handleThrowable(t);
t.printStackTrace();
return;
}
daemon = bootstrap;
} else {
// When running as a service the call to stop will be on a new
// thread so make sure the correct class loader is used to prevent
// a range of class not found exceptions.
Thread.currentThread().setContextClassLoader(daemon.catalinaLoader);
}
//根据args参数执行不同的命令
try {
String command = "start";//默认执行start
if (args.length > 0) {
command = args[args.length - 1];
}
if (command.equals("startd")) {
args[args.length - 1] = "start";
daemon.load(args);
daemon.start();
} else if (command.equals("stopd")) {
args[args.length - 1] = "stop";
daemon.stop();
} else if (command.equals("start")) {
daemon.setAwait(true);
daemon.load(args);
daemon.start();
} else if (command.equals("stop")) {
daemon.stopServer(args);
} else if (command.equals("configtest")) {
daemon.load(args);
if (null==daemon.getServer()) {
System.exit(1);
}
System.exit(0);
} else {
log.warn("Bootstrap: command \"" + command + "\" does not exist.");
}
} catch (Throwable t) {
// Unwrap the Exception for clearer error reporting
if (t instanceof InvocationTargetException &&
t.getCause() != null) {
t = t.getCause();
}
handleThrowable(t);
t.printStackTrace();
System.exit(1);
}
}
public void start()
throws Exception {
if( catalinaDaemon==null ) init(); Method method = catalinaDaemon.getClass().getMethod("start", (Class [] )null);
method.invoke(catalinaDaemon, (Object [])null); }
调用执行start方法前,先判断catalinaDaemon有没有被初始化,如果没有则执行init方法,然后使用Method进行反射调用Catalina的start方法.
知识点补充:
Method是java.lang.reflect包里的类,可以使用其中的invoke方法来执行所代表的方法,invoke里有两个参数,第一个参数是Method方法所在的实体,第二个参数是可变参数,用于Method方法执行时所需要的参数.
Catalina的启动过程
Catalina的启动主要调用setAwait,load和start方法来完成.setAwait方法用于设置Server启动后是否进入等待状态的标志,为true进入,否则不进入.load方法用于加载配置文件,start方法用于启动服务器.
public void setAwait(boolean b) {
await = b;
} public void load() {
//...创建server
try {
getServer().init();
} catch (LifecycleException e) {
if (Boolean.getBoolean("org.apache.catalina.startup.EXIT_ON_INIT_FAILURE")) {
throw new java.lang.Error(e);
} else {
log.error("Catalina.start", e);
} }
//...
} /**
* Start a new server instance.
*/
public void start() { if (getServer() == null) {
load();
} if (getServer() == null) {
log.fatal("Cannot start server. Server instance is not configured.");
return;
} long t1 = System.nanoTime(); // Start the new server
try {
getServer().start();
} catch (LifecycleException e) {
log.fatal(sm.getString("catalina.serverStartFail"), e);
try {
getServer().destroy();
} catch (LifecycleException e1) {
log.debug("destroy() failed for failed Server ", e1);
}
return;
}
//...
if (await) {
await();
stop();
}
}
Server的启动过程
Server接口中提供了addService(Service service),removeService(Service service)来增加和删除Service,Server中的init和start方法循环调用Service中的init和start方法来启动所有Service.Server的默认实现是StandardServer.
Service的启动过程
Service的默认实现是StandardService,和StandardServer一样也继承自LifecycleMBeanBase类,所以init和start方法最终会调用initInternal和startInternal方法.而StandardService中的initInternal和startInternal方法主要调用container,executors,mapperListener,connectors的init和start方法.
Tomcat声明周期管理
1.Lifecycle接口
Tomcat通过Lifecycle接口统一管理生命周期,所有生命周期组件都要实现这个接口,Lifecycle接口主要做了4件事:
1) 定义了13个String类型常量,用于LifecycleEvent事件的type属性中,作用是为了区分组件发出LifecycleEvent事件的状态.
2) 定义了3个管理监听器的方法addLifecycleListener,findLifecycleListener,removeLifecycleListener,分别用来添加,查找,删除LifecycleListener类型的监听器.
3) 定义了4个生命周期方法:init,start,stop和destroy,用于执行生命周期的各个阶段的操作.
4) 定义了获取当前状态的两个方法:getState和getStateName,用来获取当前的状态.
具体接口代码如下:
public interface Lifecycle {
//13中LifecycleEvent事件的类型
public static final String BEFORE_INIT_EVENT = "before_init"; public static final String AFTER_INIT_EVENT = "after_init"; public static final String START_EVENT = "start"; public static final String BEFORE_START_EVENT = "before_start"; public static final String AFTER_START_EVENT = "after_start"; public static final String STOP_EVENT = "stop"; public static final String BEFORE_STOP_EVENT = "before_stop"; public static final String AFTER_STOP_EVENT = "after_stop"; public static final String AFTER_DESTROY_EVENT = "after_destroy"; public static final String BEFORE_DESTROY_EVENT = "before_destroy"; public static final String PERIODIC_EVENT = "periodic"; public static final String CONFIGURE_START_EVENT = "configure_start"; public static final String CONFIGURE_STOP_EVENT = "configure_stop"; //3个管理监听器的方法
public void addLifecycleListener(LifecycleListener listener); public LifecycleListener[] findLifecycleListeners(); public void removeLifecycleListener(LifecycleListener listener); //4个生命周期方法
public void init() throws LifecycleException; public void start() throws LifecycleException; public void stop() throws LifecycleException; public void destroy() throws LifecycleException; //2个获取当前状态的方法
public LifecycleState getState(); public String getStateName();
}
2.LifecycleBase
LifecycleBase是Lifecycle的默认实现,所有实现了生命周期的组件都直接或间接的继承了LifecycleBase.LifecycleBase为Lifecycle里的接口方法提供了默认实现.监听器管理是专门提供了一个LifecycleSupport类来完成,在LifecycleSupport中定义了LifecycleListener类型的数组,用来保存所有监听器,并定义了添加,删除,查找,执行监听器的方法;生命周期中设置了相应的状态并调用了相应的模板方法,init,start,stop,destroy所对应的模板方法分别是initInternal,startInternal,stopInternal,destroyInternal方法,执行生命周期就是这4个方法.组件的当前状态在这4个方法中已经设置好了,所以直接返回就OK了.
Container分析
Container是Tomcat中容器的接口,通常使用的Servlet就封装在其子接口Wrapper中.Container一共有4个接口Engine,Host,Context,Wrapper和一个默认实现类ContainerBase,每个子接口都是一个容器,这四个容器都有一个对应的StandardXXX实现类,并且这些实现类都继承自ContainerBase类.Container还继承Lifecycle接口,而且ContainerBase间接继承LifecycleBase. 4个接口Engine,Host,Context,Wrapper也符合Tomcat的生命周期管理模式.
1.Container容器结构
2.4个容器的作用
Engine:引擎,用来管理多个站点,一个Service最多只能有一个Engine.
Host:代表一个站点,也可叫虚拟主机,通过配置Host来添加站点.
Context:代表一个应用程序,对应一套程序或者WEB-INF目录及下面的web.xml
Wraper:每个Wrapper封装着一个Servlet.
Pipeline-value管道
Container处理请求是使用Pipeline-value管道来处理的.Pipeline-value是责任链模式,区别于普通的责任链模式:
1) 每个Pipeline都有特定的Value,而且是在管道的最后执行,这个value叫做BaseValue,是不可删除的.
2) 在上层容器的BaseValue中会调用下层容器的管道.
Pipeline的实现方法
Pipeline管道的实现分为生命周期管理和处理请求两部分.
1.生命周期实现方法
Container中的Pipeline在抽象实现类ContainerBase中定义,并在生命周期的startInternal,stopInternal,destroyInternal方法中调用管道的相应生命周期方法.
2.处理请求实现方法
Pipeline调用所包含Value的invoke方法来处理请求,并且在BaseValue里又调用了子容器Pipeline所包含Value的invoke方法,直到最后调用了Wrapper的Pipeline所包含的BaseValue—StandardWrapperValue
Connector分析
Connector用于接收请求并将请求封装成Request和Response来具体处理,最底层是使用Socket来进行连接的,Request和Response是按照Http协议来封装的,所以Connector同时实现了TCP/IP协议和HTTP协议,Request和Response封装完之后交给Container进行处理,Container就是Servlet容器,Container处理完成之后返回给Connector,最后Connector使用Socket将处理结果返回给客户端,整个请求就完成了.
Connector中具体是用ProtocolHandler来处理请求,并且Connector的创建过程主要是初始化ProtocolHandler.不同的ProtocolHandler代表不同的连接类型.Http11Protocol使用的是普通的Socket来连接的.Http11NioProtocol使用的是NioSocket来连接的.
Protocol三个重要组件:
Endpoint:用于处理底层的Socket网络连接.
Processor:用于将Enpoint接收到的请求封装成Request
Adapter:用于将封装好的Request交给Container处理.
最近学习有些懈怠了,主要是工作太忙,下班后基本剩下上床睡觉了.无论如何还是要不断加强学习,提高自身技术水平.
深入分析理解Tomcat体系结构的更多相关文章
- Tomcat详解系列(2) - 理解Tomcat架构设计
Tomcat - 理解Tomcat架构设计 前文我们已经介绍了一个简单的Servlet容器是如何设计出来,我们就可以开始正式学习Tomcat了,在学习开始,我们有必要站在高点去看看Tomcat的架构设 ...
- B/S交互过程及tomcat体系结构
浏览器与服务器交互过程: 1.浏览器根据主机名,如www.baidu.com,去操作系统的hosts文件中查找主机名对应的ip地址. 2.如果查找不到,则会去互联网上的dns服务器上查找主机名对应的i ...
- [转载]理解Tomcat的Classpath-常见问题以及如何解决
摘自: http://www.linuxidc.com/Linux/2011-08/41684.htm 在很多Apache Tomcat用户论坛,一个问题经常被提出,那就是如何配置Tomcat的cla ...
- 彻底理解tomcat是怎样多线程处理http请求并将代码执行到controller里的的
彻底理解tomcat是怎样多线程处理http请求并将代码执行到controller里的的 1.线程池,thread = threadPool.getThread(),thread.executeHtt ...
- 深入理解Tomcat(12)拾遗
前言 如何使用? 源码解读 总结 前言 Tomcat为了提高性能,在接受到socket传入的字节之后并不会马上进行编码转换,而是保持byte[]的方式,在用到的时候再进行转换.在tomcat的实现中, ...
- Servlet深入学习,规范,理解和实现(中)——深入理解Tomcat(一)
心得:在写这篇博客之前.我大致阅读一些关于Tomcat的书籍和博客等资料.有些资料由于时间的关系,解说的Tomcat版本号太老.有些资料能够非常好的说明Tomcat整理结构和设计思想可是非常多重要的问 ...
- 1、Web容器的理解&Tomcat的安装与配置
Web容器的理解 <Java Web开发实战经典——基础篇>一书中对Web容器这一概念阐述得很好,借用其观点对Web容器加以理解: 想要运行一个Java Web的程序,则必须有相应的Web ...
- 由浅入深讲解责任链模式,理解Tomcat的Filter过滤器
本文将从简单的场景引入, 逐步优化, 最后给出具体的责任链设计模式实现. 场景引入 首先我们考虑这样一个场景: 论坛上用户要发帖子, 但是用户的想法是丰富多变的, 他们可能正常地发帖, 可能会在网页中 ...
- 深入理解Tomcat
简介 tomcat是一个web服务器,运行jsp和servlet,使用HTTP与客户端(通常是浏览器)进行通信. 构成 下图是tomcat的架构,可以看出:核心内容是Connector和Contain ...
随机推荐
- getParameterMap的使用
就是前端提交到Servlet或者Action里面的参数Map哈,如果你是以表单提交,那么request.getParameterMap()中将包含你表单里面所有input标签的数据,以其name为ke ...
- XShell安装(五)
Xshell就是一个远程控制Centos的软件:(用XShell比较方便,试用的都知道,界面也人性化) 详细介绍请看 百度百科 我随便百度下载了一个中文版的 给下地址 http://rj.baidu ...
- 004-RIP、OSPF【路由选择协议】
常见的路由选择协议有:RIP协议.OSPF协议. 1.RIP协议 路由信息协议(英语:Routing Information Protocol,缩写:RIP)是一种内部网关协议(IGP),为最早出现的 ...
- c# 获取网页源代码(支持cookie),最简单代码
/// /// 获取网页源码 public static string GetHtmls(string url, string referer = "", string cooki ...
- boost之时间timer
C++一直缺乏对时间和日期的处理能力,一般借助于C的struct tm和time():timer包含三个类其中timer,progress_timer是计时器类,进度指示类是progress_disp ...
- Linux服务器维护常用命令
# uname -a # 查看内核/操作系统/CPU信息 # /etc/issue # 查看操作系统版本 # cat /proc/cpuinfo # 查看CPU信息 # hostname # 查看计算 ...
- C#中字符串的内存分配与驻留池
完全引用http://www.cnblogs.com/instance/archive/2011/05/24/2056091.html 驻留池:是一张记录了所有在代码中使用字面量声明的字符串实例的引用 ...
- 解决PowerDesigner 反向工程没有注释(备注)
1. 列注释 原来代码: {OWNER, TABLE, S, COLUMN, DTTPCODE, LENGTH, SIZE, PREC, COMPUTE, NOTNULL, IDENTITY, DOM ...
- asp.net 利用Response.Filter 获取输出内容, 变更输出内容
重写 Response.Filter 就可以获取或更新输出到浏览器的内容 资料: https://weblog.west-wind.com/posts/2009/Nov/13/Captur ...
- kafka connect简介以及部署
https://blog.csdn.net/u011687037/article/details/57411790 1.什么是kafka connect? 根据官方介绍,Kafka Connect是一 ...