- 浏览: 14582 次
- 性别:
- 来自: 南京
最新评论
【转】Tomcat启动源代码分析
Tomcat的源码研读怎么说都是一件恐怖的事情,代码太多!不过管中窥豹,也可偶尔为之。谁让我好读书,不求甚解呢。前面对嵌入式Tomcat(Tomcat 4.0)进行了一个简单的分析,见在应用中使用嵌入式Tomcat。
今天的这篇文章对Tomcat的源码进行了一些分析,主要是Tomcat启动。
1、Bootstrap.java。正如OFBiz的启动程序时Start.java,Tomcat的启动程序是Bootstrap.java。OFBiz的Start.java做的事情最主要的就是加载相应的lib库和启动tomcat及其component。Tomcat的Bootstrap也是加载相应的lib库和启动Catalina
的process方法。Lib库放置在common,server和share目录中。
2、Catalina.java。这个类主要研究start方法,核心代码如下:
1 Digester digester = createStartDigester();
2 File file = configFile();
3 try {
4 InputSource is =
5 new InputSource("file://" + file.getAbsolutePath());
6 FileInputStream fis = new FileInputStream(file);
7 is.setByteStream(fis);
8 digester.push(this);
9 digester.parse(is);
10 fis.close();
11 } catch (Exception e) {
12 System.out.println("Catalina.start using "
13 + configFile() + ": " + e);
14 e.printStackTrace(System.out);
15 System.exit(1);
16 }
主要是解析server.xml文件,采用的Digester,非常著名的xml解析器。通过解析的源代码分析,Tomcat将Engine,Host和Context当成Container,这是一个虚拟的概念,具体的容器都实现了Container, Lifecycle接口。所以Service不是直接引用一个Engine,而是一个Container。在应用中使用嵌入式Tomcat的tomcat实现结构图中都是相邻层次之间都是双向引用的,如Service引用上面的Server还有下级的Connector和Container。大致类图如下:
Digester解析server.xml就是将这些实例初始化并且配置好相互的引用关系。Connector通过Container的invoke方法将接受到了请求交给Container最高层Engine处理:
CoyoteAdapter.java
connector.getContainer().invoke(request, response);
接下来就是初始化并启动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的初始化最终就是将connector进行初始化:
CoyoteConnector.java
/**
* Initialize this connector (create ServerSocket here!)
*/
public void initialize()
throws LifecycleException {
if (initialized)
throw new LifecycleException
(sm.getString("coyoteConnector.alreadyInitialized"));
this.initialized = true;
if( oname == null && (container instanceof StandardEngine)) {
try {
// we are loaded directly, via API - and no name was given to us
StandardEngine cb=(StandardEngine)container;
oname = createObjectName(cb.getName(), "Connector");
Registry.getRegistry(null, null)
.registerComponent(this, oname, null);
} catch (Exception e) {
log ("Error registering connector " + e.toString());
}
if(debug > 0)
log("Creating name for connector " + oname);
}
// Initialize adapter
adapter = new CoyoteAdapter(this);
protocolHandler.setAdapter(adapter);
IntrospectionUtils.setProperty(protocolHandler, "jkHome",
System.getProperty("catalina.base"));
// Configure secure socket factory
if (factory instanceof CoyoteServerSocketFactory) {
IntrospectionUtils.setProperty(protocolHandler, "secure",
"" + true);
CoyoteServerSocketFactory ssf =
(CoyoteServerSocketFactory) factory;
IntrospectionUtils.setProperty(protocolHandler, "algorithm",
ssf.getAlgorithm());
IntrospectionUtils.setProperty(protocolHandler, "ciphers",
ssf.getCiphers());
IntrospectionUtils.setProperty(protocolHandler, "clientauth",
ssf.getClientAuth());
IntrospectionUtils.setProperty(protocolHandler, "keystore",
ssf.getKeystoreFile());
IntrospectionUtils.setProperty(protocolHandler, "randomfile",
ssf.getRandomFile());
IntrospectionUtils.setProperty(protocolHandler, "rootfile",
ssf.getRootFile());
IntrospectionUtils.setProperty(protocolHandler, "keypass",
ssf.getKeystorePass());
IntrospectionUtils.setProperty(protocolHandler, "keytype",
ssf.getKeystoreType());
IntrospectionUtils.setProperty(protocolHandler, "protocol",
ssf.getProtocol());
IntrospectionUtils.setProperty(protocolHandler,
"sSLImplementation",
ssf.getSSLImplementation());
}
try {
protocolHandler.init();
} catch (Exception e) {
throw new LifecycleException
(sm.getString
("coyoteConnector.protocolHandlerInitializationFailed", e));
}
}
Protocol Handler初始化会初始化PoolTcpEndPoint,这个时候就会启动Tomcat的端口了:
public void initEndpoint() throws IOException, InstantiationException {
try {
if(factory==null)
factory=ServerSocketFactory.getDefault();
if(serverSocket==null) {
try {
if (inet == null) {
serverSocket = factory.createSocket(port, backlog);
} else {
serverSocket = factory.createSocket(port, backlog, inet);
}
} catch ( BindException be ) {
throw new BindException(be.getMessage() + ":" + port);
}
}
if( serverTimeout >= 0 )
serverSocket.setSoTimeout( serverTimeout );
} catch( IOException ex ) {
throw ex;
} catch( InstantiationException ex1 ) {
throw ex1;
}
initialized = true;
}
初始化后整个tomcat就做好准备启动,这时还不能处理客户端的请求,必须启动相关容器。与初始化相比,启动的时候同时启动Container和Connector。Container的启动会将Engine,Host和Conext都启动起来。
Connector启动的时候就会启动PoolTcpEndPoint,看看它的run方法就大概知道怎么回事了:
/**
* The background thread that listens for incoming TCP/IP connections and
* hands them off to an appropriate processor.
*/
public void run() {
// Loop until we receive a shutdown command
while (running) {
// Loop if endpoint is paused
while (paused) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// Ignore
}
}
// Allocate a new worker thread
MasterSlaveWorkerThread workerThread = createWorkerThread();
if (workerThread == null) {
try {
// Wait a little for load to go down: as a result,
// no accept will be made until the concurrency is
// lower than the specified maxThreads, and current
// connections will wait for a little bit instead of
// failing right away.
Thread.sleep(100);
} catch (InterruptedException e) {
// Ignore
}
continue;
}
// Accept the next incoming connection from the server socket
Socket socket = acceptSocket();
// Hand this socket off to an appropriate processor
workerThread.assign(socket);
// The processor will recycle itself when it finishes
}
// Notify the threadStop() method that we have shut ourselves down
synchronized (threadSync) {
threadSync.notifyAll();
}
}
MasterSlaveWorkerThread默认最大线程数是20,Tomcat优化时可以设置此线程数,见Tomcat优化方案。
MasterSlaveWorkerThread使用的是Guarded Suspension Pattern,如果有新的Socket分配,那么进行处理,available作为警戒条件:
synchronized void assign(Socket socket) {
// Wait for the Processor to get the previous Socket
while (available) {
try {
wait();
} catch (InterruptedException e) {
}
}
// Store the newly available Socket and notify our thread
this.socket = socket;
available = true;
notifyAll();
}
/**
* Await a newly assigned Socket from our Connector, or <code>null</code>
* if we are supposed to shut down.
*/
private synchronized Socket await() {
// Wait for the Connector to provide a new Socket
while (!available) {
try {
wait();
} catch (InterruptedException e) {
}
}
// Notify the Connector that we have received this Socket
Socket socket = this.socket;
available = false;
notifyAll();
return (socket);
}
public void run() {
// Process requests until we receive a shutdown signal
while (!stopped) {
// Wait for the next socket to be assigned
Socket socket = await();
if (socket == null)
continue;
// Process the request from this socket
endpoint.processSocket(socket, con, threadData);
// Finish up this request
endpoint.recycleWorkerThread(this);
}
// Tell threadStop() we have shut ourselves down successfully
synchronized (threadSync) {
threadSync.notifyAll();
}
}
下面一幅图有助理解,Tomcat请求客户端情况的具体分析后面再分析。
http://www.blogjava.net/persister/archive/2009/06/17/282875.html
相关推荐
源代码分析对于理解Tomcat的工作原理、优化性能或进行自定义扩展非常有价值。这里的“简单实用”可能是指通过研究源码,开发者可以更直观地了解Web服务器内部机制,从而更好地应用在实际项目中。 **Tomcat 8源代码...
3. 使用断点:在IDE中设置源代码的断点,通过启动调试模式运行Tomcat,当执行到断点时,可以查看变量状态,单步执行,跟踪调用栈。 4. 跟踪Servlet生命周期:Tomcat通过Servlet容器管理Servlet,了解Servlet的init、...
这个源代码版本提供了深入理解Tomcat工作原理的机会,对于开发者来说是一份宝贵的资源。下面将详细介绍Tomcat 6.0.41源代码中的关键组件、功能以及如何在Eclipse中进行编译和运行。 一、Tomcat架构 Tomcat由几个...
- **Server.xml配置解析**:Tomcat启动时会解析conf/server.xml,根据配置文件创建和配置容器结构。 4. **请求处理** - **Acceptor线程**:接收网络连接,创建Socket连接并将其交给Processor处理。 - **...
它的源代码是公开的,这使得开发者能够深入理解其内部工作原理,优化性能,或者为它添加自定义功能。以下是对Tomcat源码及其分析的一些关键知识点: 1. **Servlet与JSP**: Tomcat的核心在于Servlet容器,它负责...
源代码分析可以帮助我们深入理解Tomcat的工作原理,优化性能,以及进行自定义扩展。下面是关于Apache Tomcat 6.0源代码的一些关键知识点: 1. **架构概述**:Tomcat主要由Catalina、Jasper、 Coyote和Commons组件...
在深入研究Tomcat 5.5的源代码时,我们可以学习到以下几个关键知识点: 1. **Servlet和JSP规范**: Tomcat 5.5遵循Servlet 2.4和JSP 2.0规范。源代码中包含了实现这些规范的类和接口,例如`org.apache.catalina....
通过这种方式,开发者可以逐行跟踪代码,观察Tomcat启动、请求处理、响应生成等关键流程,这对于学习和优化Tomcat的工作机制非常有帮助。 【标签】"tomcat源码"强调了主题的重点,即Tomcat的原始代码,这对于Java ...
当你下载并解压Tomcat 8的源代码后,可以将其导入Eclipse或其他IDE中进行分析和学习。源代码目录结构清晰,包括`common`, `conf`, `webapps`, `work`, `logs`, `bin`, 和 `lib`等目录,它们各自承载着特定的功能。 ...
源代码分析: 1. **目录结构**: - `bin`:包含启动和停止Tomcat的脚本,如`catalina.sh`和`startup.bat`。 - `conf`:存储配置文件,如`server.xml`,定义服务器的全局配置;`web.xml`,应用级的部署描述符。 -...
这个源代码包提供了Tomcat的核心功能和组件的源码,对于深入理解Tomcat的工作原理以及进行定制化开发具有重要的价值。 源代码的分析可以从以下几个方面展开: 1. **架构概述**:Tomcat采用模块化设计,主要包括...
源代码压缩包"Tomcat与Java Web开发技术详解源代码.rar"包含了书中所有示例的完整实现,为读者提供了动手实践的宝贵资源。 首先,Tomcat是Apache软件基金会下的一个开源项目,是一款轻量级的应用服务器,主要支持...
这个源代码版本是7.0.28,它包含了开发、调试和理解Tomcat内部工作原理的所有原始代码。 在深入源代码之前,我们先了解一些基础概念。Servlet是Java编写的小型服务器端程序,负责处理来自客户端(如Web浏览器)的...
源代码的分析和研究能帮助我们深入理解其内部工作原理,尤其是对于想要构建自己的Web服务器或者优化现有Tomcat配置的人来说,更是宝贵的资源。 在Tomcat 7源代码中,我们可以找到以下几个关键的知识点: 1. **目录...
六、源代码分析 "Tomcat与Java.Web开发技术详解源代码"这个压缩包很可能包含了示例项目、Tomcat配置文件以及讲解这些概念的代码片段。通过深入研究这些源代码,开发者可以更好地理解Tomcat的工作方式,学习如何配置...
5. **源代码分析**:提供的`apache-tomcat-7.0.19-src.zip`文件包含了Tomcat的源代码,这对于开发者深入理解其工作原理、定制功能或调试问题非常有帮助。源代码分为几个主要部分,如Catalina、Commons、Jasper、NIO...
首先,Tomcat 7.0.42源代码是一个Maven项目,这意味着开发者可以利用支持Maven的集成开发环境(IDE)如IntelliJ IDEA或Eclipse,通过导入项目来直接进行阅读和分析。Maven是一个强大的项目管理和依赖管理工具,它...
标签"源码"可能意味着这篇博文还涉及到了Tomcat的源代码分析,可能讲解了如何通过查看源码理解服务安装的过程。"工具"标签可能指的是使用的一些辅助工具,如服务管理工具或日志分析工具。 9. **安全注意事项**: ...
3. **源代码分析**: - **核心组件**:如Catalina(负责处理Servlet容器的核心逻辑)、 Coyote(处理HTTP请求/响应)、 Jasper(处理JSP编译)。 - **生命周期管理**:Tomcat如何启动、停止,以及容器内部对象的...
9. "Tomcat启动源代码分析.pdf":深入到启动脚本和Java代码,解释了从启动脚本开始,如何初始化和启动Tomcat服务的全过程。 10. "tomcat类加载机制.pdf":再次聚焦于Tomcat的类加载机制,可能深入到更多细节和技巧...