分享tomcat源码系列一

原文连接:http://simpleframework.net/blog/v/16313.html

最近在看Tomcat的源码,下面用博客记下看源码的一些心得。

Tomcat是从org.apache.catalina.startup.Bootstrap#main()开始启动.大致分为三个步骤,即init、load和start。代码如下:

Java代码

publicstaticvoidmain(Stringargs[]){

try{

//AttempttoloadJMXclass

newObjectName("test:foo=bar");

}catch(Throwablet){

System.out.println(JMX_ERROR_MESSAGE);

try{

//Giveuserssometimetoreadthemessagebeforeexiting

Thread.sleep(5000);

}catch(Exceptionex){

}

return;

}

if(daemon==null){

daemon=newBootstrap();

try{

daemon.init();★1

}catch(Throwablet){

t.printStackTrace();

return;

}

}

try{

Stringcommand="start";

if(args.length>0){

command=args[args.length-1];

}

if(command.equals("startd")){

args[0]="start";

daemon.load(args);

daemon.start();

}elseif(command.equals("stopd")){

args[0]="stop";

daemon.stop();

}elseif(command.equals("start")){

daemon.setAwait(true);

daemon.load(args);★2

//反射调用Catalina的start方法

daemon.start();★3

}elseif(command.equals("stop")){

daemon.stopServer(args);

}

}catch(Throwablet){

t.printStackTrace();

}

}

从以上可以很清楚的看出tomcat是通过参数的不同进行相应的命令调用。

★1启动、初始化(加载类)

启动之前要进行相应的init()初始化,进行相应的环境设置以及包的加,以下是init()方法。(org.apache.catalina.startup.Bootstrap.init())

Java代码

publicvoidinit()

throwsException

{

setCatalinaHome();//设置Catalina安装目录

setCatalinaBase();//设置Catalina工作目录

initClassLoaders();//加载jar包

//将classload设置进线程,以便我们使用时进行调用

Thread.currentThread().

setContextClassLoader(catalinaLoader);

SecurityClassLoad.securityClassLoad(catalinaLoader);

//加载启动类和调用它的process方法

if(log.isDebugEnabled())

log.debug("Loadingstartupclass");

ClassstartupClass=

catalinaLoader.loadClass

("org.apache.catalina.startup.Catalina");

ObjectstartupInstance=startupClass.newInstance();

//设置共享扩张类加载器

if(log.isDebugEnabled())

log.debug("Settingstartupclassproperties");

Stringmethodname="setParentClassLoader";

ClassparamTypes[]=newClass[1];

paramTypes[0]=Class.forName("java.lang.ClassLoader");

ObjectparamValues[]=newObject[1];

paramValues[0]=sharedLoader;

Methodmethod=

startupInstance.getClass().getMethod(methodName,

paramTypes);

method.invoke(startupInstance,paramValues);

catalinaDaemon=startupInstance;

}

在加载jar的时候,需要初始化classloader,代码如下:(org.apache.catalina.startup.Bootstrap)

Java代码

privatevoidinitClassLoaders(){

try{

commonLoader=createClassLoader("common",null);

catalinaLoader=createClassLoader("server",commonLoader);

sharedLoader=createClassLoader("shared",commonLoader);

}catch(Throwablet){

log.error("Classloadercreationthrewexception",t);

System.exit(1);

}

}

tomcat中的加载方式是:

|-------commonLoader(common)->SystemLoader

|-------sharedLoader(shared)->commonLoader->SystemLoader

|-------catalinaLoader(server)->commonLoader->SystemLoader

Common是公共类加载器,负责加载tomcat内部和web应用程序可以看到的类(%CATALINA_HOME%/bin/common下的jar文件),Catalina负责加载的是tomcat内部使用的类(%CATALINA_HOME%/server下的jar文件),这些类对web应用程序不可见。Shared负责加载的是web应用程序之间共享的类(%CATALINA_BASE%/shared下的jar文件),这些类对于tomcat内部是不可见的。如果%CATALINA_HOME%/conf/catalina.Properties中没有指定Common的搜索路径,则用当前的类的类加载器即系统类加载器作为Common。

★2装载相应的资源

下面主要讲解tomcat的load()方法。下图是Catalina.load方法的时序图。

(1)从上面的时序图可以看出首先调用Catalina类的load()方法,具体代码如下:

(org.apache.catalina.startup.Catalina)。

Java代码

publicvoidload(){

initDirs();

//Beforedigester-itmaybeneeded

initNaming();

//CreateandexecuteourDigester

Digesterdigester=createStartDigester();

try{

inputSource.setByteStream(inputStream);

digester.push(this);

digester.parse(inputSource);//对server.xml进行解析

inputStream.close();

}

......

//Startthenewserver

if(serverinstanceofLifecycle){

try{

server.initialize();//server初始化工作

}catch(LifecycleExceptione){

log.error("Catalina.start",e);

}

}

longt2=System.currentTimeMillis();

log.info("Initializationprocessedin"+(t2-t1)+"ms");

}

(2)在上面的load()方法中需要进行server的初始化工作,下图为Catalina.initialize的时序图,从图中可以看出server初始化所完成的工作。

至此,load方法结束,初期化的工作结束,下面开始进入start方法。

★3容器启动

容器启动时,会调用Catalina.start(),下图为它的时序图。从图中可以看出StandardService的start方法被调用后会分别对Container和Connector进行start方法的调用。

1.Bootstrap调用Catalina的start方法

Catalina.start()方法(org.apache.catalina.startup.Catalina.start())

Java代码

publicvoidstart(){

//启动server

if(serverinstanceofLifecycle){

try{

((Lifecycle)server).start();

......

}

2.Catalina调用StandardServer的start方法

StandardServer.start()(org.apache.catalina.core.StandardServer.start())

Java代码

publicvoidstart()throwsLifecycleException{

synchronized(services){

for(inti=0;i<services.length;i++){

if(services[i]instanceofLifecycle)

((Lifecycle)services[i]).start();

}

}

3.StandardServer调用StandardService的start方法

Java代码

org.apache.catalina.core.StandardService.start())

publicvoidstart()throwsLifecycleException{

if(container!=null){

synchronized(container){

if(containerinstanceofLifecycle){

//standardEngine的启动

((Lifecycle)container).start();

}

}

//两个connector的启动,8080和8009

synchronized(connectors){

for(inti=0;i<connectors.length;i++){

if(connectors[i]instanceofLifecycle)

((Lifecycle)connectors[i]).start();

}

}

}

以上StandardService.start()方法主要实现了两个功能,standardEngine的启动和connector的启动,下面分别来介绍。

相关推荐