- 浏览: 26426 次
- 性别:
- 来自: 广州
最新评论
在前面的大部分文章都是讲连接器和容器的,以后的内容会偏向写一些Tomcat的其他组件以及一些细节的东西。
Tomcat有很多组件,要一个一个启动组件难免有点麻烦。由于Tomcat的包含关系是Catalina->Server->Service->容器/连接器/日志器等,于是可通过父组件负责启动/关闭它的子组件,这样只要启动Catalina,其他的都自动启动了。这种单一启动和关闭的机制是通过实现Lifecycle接口来实现的。下面是Lifecycle接口的定义:
public interface Lifecycle { 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 void addLifecycleListener(LifecycleListener listener);//在此组件中添加一个监听器 public LifecycleListener[] findLifecycleListeners(); public void removeLifecycleListener(LifecycleListener listener); public void start() throws LifecycleException;//组件启动方法 public void stop() throws LifecycleException; }
当组件实现了Lifecycle接口,父组件启动的时候,即调用start方法时,只要在父组件的start方法中也调用子组件的start方法即可(只有实现统一的接口Lifecycle才能实现统一调用,如以下调用方式:(Lifecycle)子组件.start()),下面一步一步来看源代码,首先在Catalina启动start,部分代码如下:
// Start the new server if (server instanceof Lifecycle) { try { server.initialize(); ((Lifecycle) server).start();//启动server try { // Register shutdown hook Runtime.getRuntime().addShutdownHook(shutdownHook); } catch (Throwable t) { // This will fail on JDK 1.2. Ignoring, as Tomcat can run // fine without the shutdown hook. } // Wait for the server to be told to shut down server.await(); } catch (LifecycleException e) { System.out.println("Catalina.start: " + e); e.printStackTrace(System.out); if (e.getThrowable() != null) { System.out.println("----- Root Cause -----"); e.getThrowable().printStackTrace(System.out); } } }
关键看((Lifecycle) server).start();这样便在启动Catalina的时候启动了Server,再看StandardServer的start方法:
public void start() throws LifecycleException { // Validate and update our current component state if (started) throw new LifecycleException (sm.getString("standardServer.start.started")); // Notify our interested LifecycleListeners //发送这个事件 lifecycle.fireLifecycleEvent(BEFORE_START_EVENT, null);//发送生命周期事件。 lifecycle.fireLifecycleEvent(START_EVENT, null); started = true; // Start our defined Services synchronized (services) { //由这里也可以看出一个server可以有多个services for (int i = 0; i < services.length; i++) { if (services[i] instanceof Lifecycle) ((Lifecycle) services[i]).start(); } } // Notify our interested LifecycleListeners lifecycle.fireLifecycleEvent(AFTER_START_EVENT, null); }
主要做了两件事,1:发送生命周期事件给监听者;2:启动子组件services(至于server怎么关联上services请看前面的几篇文章,以后都不再题怎么关联上的了)。
这里先岔开一下,说一下监听器,lifecycle是一个工具类LifecycleSupport的实例,每一个组件都有这样一个工具类,这个工具类的作用就是帮助管理该组件上的监听器,包括添加监听器和群发事件给监听器,看LifecycleSupport类的一些关键代码:
public final class LifecycleSupport { public LifecycleSupport(Lifecycle lifecycle) { super(); this.lifecycle = lifecycle; } private LifecycleListener listeners[] = new LifecycleListener[0]; public void addLifecycleListener(LifecycleListener listener) { //向listeners添加监听器 synchronized (listeners) { LifecycleListener results[] = new LifecycleListener[listeners.length + 1]; for (int i = 0; i < listeners.length; i++) results[i] = listeners[i]; results[listeners.length] = listener; listeners = results; } } public void fireLifecycleEvent(String type, Object data) {//群发事件给监听器 LifecycleEvent event = new LifecycleEvent(lifecycle, type, data); LifecycleListener interested[] = null; synchronized (listeners) { interested = (LifecycleListener[]) listeners.clone(); } for (int i = 0; i < interested.length; i++) interested[i].lifecycleEvent(event);//发送组件生命周期事件。 } }
先看构造方法,传入一个lifecycle,因为每个组件都实现了lifecycle,所以这里传入的实际上是一个组件,即每个组件都有一个LifecycleSupport与之关联,当要在组件中添加一个监听器的时候,实际上是添加进工具类LifecycleSupport的一个监听器数组listeners中,当要发送一个组件生命周期的事件时,工具类就会遍历监听器数组,然后再一个一个的发送事件。这里需要先实现我们自己的监听器类并且添加进我们需要监听的组件当中。实现监听器类只要实现LifecycleListener接口就行,这个接口只有一个方法:
public interface LifecycleListener { public void lifecycleEvent(LifecycleEvent event); }
我们需要做的就是实现LifecycleListener接口来拥有自己的监听器,在lifecycleEvent方法里写自己监听到事件后该做的事情,然后添加进要监听的组件就行,比如当我们要看StandardServer是否启动了,在上面StandardServer的start方法有一句这样的代码:lifecycle.fireLifecycleEvent(START_EVENT, null);即发送StandardServer启动的事件给跟它关联的监听器。接下来回到一开始,当server启动后,接着启动它的子组件service,即调用StandardService的start方法,这个方法跟StandardServer的start方法差不多,只是启动了连接器和容器,连接器的start方法在前面的文章已经讲过了,主要是启动了n个处理器HttpProcessor组件。顶级容器是StandardEngine,它的start方法仅仅调用了父类ContainerBase的start方法,下面看ContainerBase的start方法:
public synchronized void start() throws LifecycleException { // Validate and update our current component state if (started) throw new LifecycleException (sm.getString("containerBase.alreadyStarted", logName())); // Notify our interested LifecycleListeners lifecycle.fireLifecycleEvent(BEFORE_START_EVENT, null); addDefaultMapper(this.mapperClass); started = true; // Start our subordinate components, if any if ((loader != null) && (loader instanceof Lifecycle)) //启动所有其他的组件 ((Lifecycle) loader).start(); if ((logger != null) && (logger instanceof Lifecycle)) ((Lifecycle) logger).start(); if ((manager != null) && (manager instanceof Lifecycle)) ((Lifecycle) manager).start(); if ((cluster != null) && (cluster instanceof Lifecycle)) ((Lifecycle) cluster).start(); if ((realm != null) && (realm instanceof Lifecycle)) ((Lifecycle) realm).start(); if ((resources != null) && (resources instanceof Lifecycle)) ((Lifecycle) resources).start(); // Start our Mappers, if any Mapper mappers[] = findMappers(); for (int i = 0; i < mappers.length; i++) { if (mappers[i] instanceof Lifecycle) ((Lifecycle) mappers[i]).start(); } // Start our child containers, if any Container children[] = findChildren(); for (int i = 0; i < children.length; i++) { if (children[i] instanceof Lifecycle) ((Lifecycle) children[i]).start(); } // Start the Valves in our pipeline (including the basic), if any if (pipeline instanceof Lifecycle) ((Lifecycle) pipeline).start(); // Notify our interested LifecycleListeners lifecycle.fireLifecycleEvent(START_EVENT, null); // Notify our interested LifecycleListeners lifecycle.fireLifecycleEvent(AFTER_START_EVENT, null); }
这里代码比较丰富,由它启动了Tomcat其他所有的组件,包括加载器,映射器,日志记录器,管道等等,由这里也可以看出,他们都实现了Lifecycle接口。统一关闭跟统一启动的逻辑差不多,这里就不再说了。至此,我们对Tomcat怎么实现统一启动/关闭应该有一个比较清晰的认识了!
发表评论
-
Tomcat源码分析(一)--服务启动
2012-07-05 11:11 430对Tomcat感兴趣是由 ... -
Tomcat源码分析(二)--连接处理
2012-07-06 08:35 387目标:在这篇文章希望搞明白http请求到tomcat后是 ... -
Tomcat源码分析(三)--连接器是如何与容器关联的?
2012-07-06 11:18 537这篇文章要弄懂一个问题,我们知道,一个链接器是跟一个容器关 ... -
Tomcat源码分析(四)--容器处理链接之责任链模式
2012-07-07 16:21 359目标:在这篇文章希望搞明白connector.getCont ... -
Tomcat源码分析(五)--容器处理连接之servlet的映射
2012-07-08 09:32 396本文所要解决的问题:一个http请求过来,容器是怎么知道选 ... -
Tomcat源码分析(六)--日志记录器和国际化
2012-07-09 08:34 487日志记录器挺简单的,没有很多东西,最主要的就是一个Lo ... -
Tomcat源码分析(八)--载入器
2012-07-10 20:14 520在讲Tomcat的载入器之前,先要了解一下java的类加载 ... -
Tomcat源码分析(十)--部署器
2012-07-12 09:02 489我们知道,在Tomcat的世界里,一个Host容器代表一 ... -
Tomcat源码分析(九)--Session管理
2012-07-11 15:16 644在明白Tomcat的Session机 ...
相关推荐
开发工具 apache-tomcat-8.0.41-windows-x86开发工具 apache-tomcat-8.0.41-windows-x86开发工具 apache-tomcat-8.0.41-windows-x86开发工具 apache-tomcat-8.0.41-windows-x86开发工具 apache-tomcat-8.0.41-...
tomcat 6/7/8 自带防暴力破解机制,通过塞满cache,挤出已锁定账号,实现完美绕过。
tomcat-redis-session-manager源码
apache-tomcat-8.0.21 32/64安装版
在网上搜索一堆文章没找到解决方法,只找到了tomcat7-maven-plugin的plugin,如下: <groupId>org.apache.tomcat.maven</groupId> <artifactId>tomcat7-maven-plugin</artifactId> <version>2.2</version> </...
apache-tomcat-7.0.53apache-tomcat-7.0.53apache-tomcat-7.0.53apache-tomcat-7.0.53
apache-tomcat-8.0.14_8081/apache-tomcat-8.0.14_8082为两个tomcat 服务器,修改目录中context.xml中redis连接地址和密码,直接可以在本地运行tomcat-->start.bat,直接访问...
tomcat6-dta-ssl-1.0.0.jar 此类文件将有助于tomcat支持ssl协议
apache-tomcat-8.5.20.tar.gz源码包和context.xml文件,这套配置是我自己亲测可用的。。另外我用的redis4这个版本。注意:如果你使用的TOMCAT其他版本。例如tomcat6或者7这套JAR包可能不可用,tomcat8.0没有测试。...
2018/7/10目前最新tomcat9.0,是一个压缩包,能够直接进行解压使用,无需下载安装。
文件名写错了,此压缩文件支持tomcat8.5。是否支持8.0请自行测试,本人只测试了8.5,可以使用。压缩文件包括tomcat-redis-session-manager-master-2.0.0.jar、jedis-2.7.3.jar、commons-pool2-2.3.jar三个jar包使用...
apache-tomcat-6.0.41-windows-x64.zip apache-tomcat-7.0.54-windows-x64.zip apache-tomcat-8.0.9-windows-x64.zip windows 64 位 tomcat 6、7、8
Tomcat8亲测可用 tomcat-redis-session-manager的jar包 修改了tomcat-redis-session-manager源码进行的编译生成的jar包
安装tomcat7 下载地址:http://tomcat.apache.com/ cd /usr/local/src/tarbag tar zxvf apache-tomcat-7.0.28.tar.gz -C ../software/ cd ../software cp -rp apache-tomcat-7.0.28/ /usr/local/ cd /usr/local/...
Tomcat->Web服务器->API->英文版->此资料仅供参考
1.添加 redis session 集群依赖的jar包到 tomcat/lib 目录下 tomcat-redis-session-manager-2.0.0.jar jedis-2.5.2.jar commons-pool2-2.2.jar 2.修改 conf 目录下的 context.xml 文件 ...
解压即可使用 操作系统 64位,win7
用于配置 tomcat-redis-session-manager
解决方案:二、Tomcat启动成功无法访问 一、报错问题解: 1.报错 Using CLASSPATH: /...
Tomcat 服务器是一个免费的开放源代码的Web 应用服务器,属于轻量级应用服务器,在中小型系统和并发访问用户不是很多的场合下被普遍使用,是开发和调试JSP 程序的首选。对于一个初学者来说,可以这样认为,当在一台...