前几天为了解决sinpool兄的《多线程的问题。》一帖,专门看了一下tomcat 4.1.30的源码,
其中重点研究了tomcat的启动这一部分,个人感觉tomcat的源码还是写的很清楚易懂,值得一看。
(以前看过struts的部分代码,感觉也比较经典)
然后我看后的代码整理了一下,附在下面,希望对其他人有用,也希望感兴趣的兄弟可以多看看好的代码,
肯定对自己的程序设计和代码质量颇有益处。
一. 启动类(包含main()方法的类):
org.apache.catalina.startup.Bootstrap
这个类是tomcat的启动类,主要按照如下步骤,进行主要的启动工作:
1. 创建3个ClassLoader:common,catalina和share,它们对应tomcat的3个Classloader,我想对tomcat
的classloader有研究的兄弟对这个肯定不陌生,其中common classloader是紧跟在系统的classloader(也就是
系统环境变量中设置的CLASSPATH所对应的classloader),而catalina classloader是common的子classloader,是tomcat
运行所需要的类的classloader,而shared classloader也是common的子classloader,是和catalina平级的classloader,
之所以说是shared classloader,是因为它是所有tomcat下面发布的webapp classloader(每一个web app都有一个自己的classloader)
的父classloader。它们这3个classloader分别读取tomcat home下面的common, server和shared三个目录里面的classes和lib目录,
用于初始化自己所控制的类库和资源。
2. 创建启动一个的org.apache.catalina.startup.Catalina类的实例,并调用它的process方法,这里使用的是java的reflection技术。
然后调用这个实例的process方法,并把Bootstrap接受到的命令行参数传递进去了,这里Bootstrap类并没有解析传给它的命令行参数。
当然在调用process之前还使用setParentClassLoader方法设置了一下父classloader。这里简单介绍一下有关classloader的一个重要
特性,就是如果classloader要load一个类时,不是自己先找,而是先把这个任务委派给自己的父classloader,然后自己的父classloader
也不找,在把这个任务委派给自己的父classloader,直到找到最顶层的classloader,然后再自顶向下的找对应的这个要load的类的定义,
如果那个classloader先找到,就返回。所以接合上面第一点介绍的tomcat中3个classloader,大家就可以明白tomca的classloader找类
的顺序了,这个对程序开发人员来说特别重要。我想使用过tomcat或者其他app server的兄弟肯定碰到过一个类明明存在可就是找不到,
或者总是找到一个老的版本,我想主要是在多个地方放置的原因,或者哪里有重名的类:-)
二.org.apache.catalina.startup.Catalina类
现在程序转到org.apache.catalina.startup.Catalina类里面的process方法。
这个方法首先设置一下catalina的home和base目录,然后通过arguments方法解析命令行参数,
最后调用execute()方法启动server。而execute方法很简单,就是根据arguments解析的命令行参数,
决定是启动server,还是stop server,如果是start server,就调用start方法,而下面重点讲一下这个start()方法,
因为才算是一个真正开始的启动tomcat的地方:-)
1. start方法首先使用Digester(这个东东是jakarta commons里面的一个用于解析xml文件的工具包,一开始是专门用于解析struts配置文件的,
后来被抽象成现在的一个通用工具,主要还是用来解析xml配置文件,根据一些定义的rule自动生成对应的类的实例,具体信息可以参考
apache网站上的文档)来设置tomcat配置文件,也就是/conf/server.xml这个文件的解析规则
然后通过如下代码来将配置文件中的数据转化成内存中的实例:
代码:
File file = configFile();
try {
InputSource is =
new InputSource("file://" + file.getAbsolutePath());
FileInputStream fis = new FileInputStream(file);
is.setByteStream(fis);
digester.push(this);
digester.parse(is);
fis.close();
} catch (Exception e) {
System.out.println("Catalina.start: " + e);
e.printStackTrace(System.out);
System.exit(1);
}
转换的规则如下(我只作一些简单的介绍),例如配置文件中的
a. Server对应可以产成一个org.apache.catalina.core.StandardServer类(这个类很重要,是tomcat server的实现)
b. Server/GlobalNamingResources对应生成org.apache.catalina.deploy.NamingResources类
而大家比较熟悉的监听8080端口的类配置如下:
c. Server/Service/Connector:org.apache.catalina.connector.http.HttpConnector
d. Server/Service/Engine/Host/Context/:org.apache.catalina.core.StandardContext
有兴趣的兄弟可以参考jakarta commons里面的Digester文档和org.apache.catalina.startup.Catalina
这个类里面的createStartDigester方法.
在这段代码之后,一个叫server的变量已经通过Digester工具生成了,它将会用于启动tomcat。
2. 然后程序进行了一些server启动前的设置工作,例如重定向log输出流等等。而server启动的代码如下:
代码:
// Start the new server
if (server instanceof Lifecycle) {
try {
server.initialize();
((Lifecycle) server).start();
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);
}
}
}
其中server这个变量就是在刚才Digester解析时创建好的。
(当时这个地方我看了很长时间,后来才发现是这样的,因为以前不太了解Digester这个东东)。
然后大家可以看到server启动主要是分3步:
1. initialize方法进行server启动的初始化操作
2. start方法启动server,主要是server中的的service和service中的connector
3. await方法等待server shutdown
其中我重点给大家介绍一下initialize方法和start方法
initialize方法:
这里面只有一个主要任务,就是逐次调用server中所有定义的service的initialize方法,
而每个service的initialize方法中调用这个service中定义的所有connector的initialize方法,
而connector的initialize方法则是创建一个serversocket用于接受客户端的请求就结束了。
如果大家看一下tomcat下面conf/server.xml,就可以发现,tomcat默认只定义了一个service叫做Tomcat-Standalone,
而下面只有默认定义了3个connector:
1. 8080端口的http connector
2. 8443端口的http ssl connector
3. 8009端口的Coyote/JK2 AJP 1.3 Connector
我想大家对这3个端口一定不陌生吧。
start方法:
这个方法里面有一个tomcat很重要,也是我认为tomcat设计对一个亮点,就是Lifecycle这个东东,它很象一个bus(总线)。
我想大家进行过程序设计的一定知道,开始设计的时候总要根据一个原则分出几个模块来,是为了代码分块,或者将
一部分功能相似的代码组织成一个模块,这样比较清楚,例如一个进销存系统会有采购,销售,库存和财务等模块,但是
我想很多人也碰到过这样的情况就是虽然分了模块但是如果在开发完毕以后,另外一个客户说只想要其中的销售模块,我想
大部分的开发人员肯定傻眼,因为虽然当时设计的时候分了模块,但是这些模块编写的时候却是交织在一起,互相的接口定义
很模糊,基本上都是直接调用另一个模块的方法,这样肯定分不开。而tomcat的这个Lifecycle的设计理念就可以解决这个问题的
一部分,它的原理就象是一个bus(总线),例如一个模块做完一个动作以后,例如销售模块创建好一个订单后,本来要直接调用
库存模块的api锁住一部分库存(我只是随便举个例子,实际业务不一定是这样),这样销售模块就需要依赖库存模块了。但是使用了
bus方式。我们就可以在订单创建后,向bus上发送一个订单创建的消息,而总线有一个事件注册机制,有点象swing的event,listener,
例如库存模块有一个listener专门用于监听订单创建的消息,进行处理,这样2个模块就互不依赖了。有兴趣的兄喜可以看看jcp上面
的一个叫做infobus的专题。
当然这个方式只是解决有效降低模块偶合度的一个方面(因为有的时候必须要直接调用另外一个模块的接口,
例如库存模块一定要直接缺德一个销售订单的信息,那么就需要定义一个接口类来描述订单的详细信息啦,这里就不具体解释了,
有空可以专门发个帖子跟大家探讨这个问题:-) ),就是不要显式触发另一个模块的某个动作,而是通过bus机制来发送消息,
而每个模块都有一个自己的handler,会监听bus,对自感兴趣的事件进行处理。tomcat的Lifecycle就是这个东西。
下面再回到start方法:
1. 它首先向总线发送了2个事件:BEFORE_START_EVENT和START_EVENT
2. 然后调用每个service的start方法,最后发送AFTER_START_EVENT消息通知其他程序
而service的start方法主要进行的动作如下:
1. 发送BEFORE_START_EVENT消息
2. 调用container的start方法
3. 然后调用connector的start方法
4. 最后发送AFTER_START_EVENT消息.
而connector的start方法就是大家最熟悉的socket编程了,大家可以参看org.apache.catalina.connector.http.HttpConnector这个类,
主要是使用java里面的多线程操作,初始化一个HttpProcessor的线程池,然后通过wait方法阻塞住每个HttpProcessor线程,只有
当接受到一个http请求时,在通过notify方法激活HttpProcessor线程,让其处理用户的http请求。
到此为止主要简单介绍了一下tomcat 4.1.30的启动过程
分享到:
相关推荐
运行`jakarta-tomcat-4.1.30.exe`,确保在安装过程中,选择的JDK路径与之前安装的JDK路径一致(即`D:\j2sdk`)。设置Tomcat的安装路径,例如`d:\tomcat`。 **3. 配置类库** 将必要的类库如`classes2.jar`(Oracle...
请下载,以备急用。 后缀加上.exe就可以运行了。
【标题】:“Jakarta Tomcat 4.1.30”的历史与技术解析 【描述】:Jakarta Tomcat 4.1.30 是一个历史悠久的Java Web服务器和应用服务器,它主要用于运行基于Servlet和JSP(JavaServer Pages)的应用程序。这个版本...
linux安装jakarta-tomcat-4.1.30.tar.gz
【Jakarta Tomcat 4.1.31】是一个经典的Java Web服务器和应用服务器,它在2000年代初期广泛被开发者使用。Tomcat是Apache软件基金会的Jakarta项目的一部分,它实现了Java Servlet和JavaServer Pages(JSP)规范,...
自己亲身使用过的,jakarta-tomcat-4.1.30,tomcat-5.0.28,apache-tomcat-5.5.28,apache-tomcat-6.0.18,apache-tomcat-7.0.73-windows-x64,apache-tomcat-8.5.32-windows-x64,apache-tomcat-9.0.10-windows-x64
4. **目录结构**:在解压的Tomcat 4.1.30中,`webapps`目录存放Web应用,`conf`目录存放配置文件,`logs`记录日志,`temp`用于临时文件,`work`存储编译后的JSP页面。 5. **安全性**:Tomcat 4.1支持基本的安全特性...
如果你用的是 CC2.2 版本,那么在%CC_HOME%\reporting\jsp\dist 目录下...假使我们用 Tomcat 4.1.30 作为JSP 服务器,该版本的Tomcat 支持 JSP1.2 规范,因此需要修 改%CC_HOME%\reporting\jsp\buildresults.jsp 文件
- 版本:jakarta-tomcat-4.1.30.exe - Tomcat版本的选择较为关键,不恰当的选择可能会导致安装失败或运行不稳定。 4. **PHP** - 版本:php-4.3.3-Win32.zip - PHP版本选择相对简单,直接下载解压即可完成安装...
启动Tomcat - 在浏览器中输入 http://localhost:8080,如果能够正常显示Tomcat欢迎页面,则表示Tomcat安装成功。 ### 三、集成SQL Server 2000支持 #### 1. 下载与安装SQL Server 2000 JDBC驱动 - 通过搜索引擎...
netty依赖库,导入一包全局无忧。
- **平台软件**:运行Red Hat Linux V9.0操作系统,JDK 1.4.2作为Java支持,Tomcat 4.1.30作为Web服务器,MySQL数据库系统。 - **应用软件**:主要运行深圳市嘉讯软件有限公司的“Minos移动信息综合运营系统”。 ...
Tomcat用于处理JSP和Servlet,这里推荐使用jakarta-tomcat-4.1.30.exe版本。安装完成后,需要配置Tomcat的环境变量,如CATALINA_HOME,指向Tomcat的安装目录。同时,确保Tomcat服务能够正常启动和停止。 **Apache与...
Netty 官方最新版本4.1.30。Netty提供异步的、事件驱动的网络应用程序框架和工具,用以快速开发高性能、高可靠性的网络服务器和客户端程序。
这份指南详细阐述了在IIS(Internet Information Services)6.0上集成Tomcat4.1.30来运行ArcIMS 9.0的步骤,这对于系统管理员来说是安装和配置ArcIMS的必备参考资料。 通过这些资源,开发者不仅可以了解ArcIMS的...
Jakarta Tomcat 4.1.30是用于运行JSP应用的服务器。同样使用`tar`解压缩,然后将Tomcat配置为Apache的插件,以便它们可以协同工作。这通常涉及配置`conf/server.xml`和`conf/catalina.properties`等文件,以及安装`...
1. **启动Tomcat**:安装并配置好环境变量后,可以通过Tomcat的管理界面或命令行工具启动Tomcat服务。启动成功后,可以通过浏览器访问`http://localhost:8080`来查看Tomcat的欢迎页面。 2. **部署JSP应用**:部署...
Potplayer关联图标PotIcons.dll之QVOD4.1.30+ICO 更多图标请访问我的空间: http://hi.baidu.com/yuwobixing/blog/item/49235dec6a1b522c279791c4.html
选择Apache + Tomcat组合时,可通过运行安装包内的`SetupApache2.0.46Tomcat4.1.30Jdk1.4.2_03`中的`Setup.exe`来自动完成Apache、JDK和Tomcat的安装与配置。默认端口为8085,建议不要修改,除非需通过编辑Apache和...
solr4.4版本,解压后可以放于tomcat下运行,可以配置数据库连接及SQL语句,将查询结果放在solr中缓存,项目直接操作solr,可以配置定时任务(PS:定时任务只支持到4.4版本,以后版本目前没有)solr作为数据库和项目...