当前位置: > Linux服务器 > Tomcat >

Tomcat学习之启动过程

时间:2014-12-30 13:34来源:linux.it.net.cn 作者:IT

startup.bat

当我们启动tomcat一般是运行%TOMCAT_HOME%\bin\startup.bat文件,这个文件实际上调用了%TOMCAT_HOME%\bin\catalina.bat批处理文件:

 

[java] view plaincopyprint?
 
  1. set "EXECUTABLE=%CATALINA_HOME%\bin\catalina.bat"  
  2. ......  
  3. set CMD_LINE_ARGS=  
  4. :setArgs  
  5. if ""%1""=="""" goto doneSetArgs  
  6. set CMD_LINE_ARGS=%CMD_LINE_ARGS% %1  
  7. shift  
  8. goto setArgs  
  9. :doneSetArgs  
  10.   
  11. call "%EXECUTABLE%" start %CMD_LINE_ARGS%  
startup.bat将start命令和控制台的所有参数都传给了catalina.bat文件,下面来看catalina.bat文件中是怎么启动Tomcat的?注意到下面这句
[java] view plaincopyprint?
 
  1. %_EXECJAVA% %JAVA_OPTS% %CATALINA_OPTS% %JPDA_OPTS% %DEBUG_OPTS% -Djava.endorsed.dirs="%JAVA_ENDORSED_DIRS%" -classpath "%CLASSPATH%" -Djava.security.manager -Djava.security.policy=="%SECURITY_POLICY_FILE%" -Dcatalina.base="%CATALINA_BASE%" -Dcatalina.home="%CATALINA_HOME%" -Djava.io.tmpdir="%CATALINA_TMPDIR%" %MAINCLASS% %CMD_LINE_ARGS% %ACTION%  

_EXECJAVA=_RUNJAVA="%JRE_HOME%\bin\java",这是在%TOMCAT_HOME%\bin\setclasspath.bat文件中设置的,也就是说这句要运行一个JAVA程序,后面紧接着就应该是运行的类%MAINCLASS%,MAINCLASS=org.apache.catalina.startup.Bootstrap,不错org.apache.catalina.startup.Bootstrap类正是Tomcat的入口类,Tomcat正是从Bootstrap类的main方法开始运行的。

 

Bootstrap

下面来看看Bootstrap的main方法做了哪些事情:

[java] view plaincopyprint?
 
  1.  public static void main(String args[]) {  
  2.     if (daemon == null) {  
  3.         Bootstrap bootstrap = new Bootstrap();  
  4.         try {  
  5.             bootstrap.init();  
  6.         } catch (Throwable t) {  
  7.             handleThrowable(t);  
  8.             t.printStackTrace();  
  9.             return;  
  10.         }  
  11.         daemon = bootstrap;  
  12.     }  
  13.   
  14.     try {  
  15.        ...  
  16.         if (command.equals("start"))  
  17.            daemon.start();  
  18.        ...  
  19.     } catch (Throwable t) {  
  20.         ...  
  21.     }  
  22. }  
从以上代码可以看出main方法做了3件事情:

 

1、初始化;

2、装配tomcat容器

3、启动tomcat容器

 

初始化

[java] view plaincopyprint?
 
  1. public void init()  
  2.     throws Exception  
  3. {  
  4.   
  5.     // Set Catalina path  
  6.     setCatalinaHome();  
  7.     setCatalinaBase();  
  8.   
  9.     initClassLoaders();  
  10.   
  11.     Thread.currentThread().setContextClassLoader(catalinaLoader);  
  12.   
  13.     SecurityClassLoad.securityClassLoad(catalinaLoader);  
  14.   
  15.     // Load our startup class and call its process() method  
  16.     if (log.isDebugEnabled())  
  17.         log.debug("Loading startup class");  
  18.     Class<?> startupClass =  
  19.         catalinaLoader.loadClass  
  20.         ("org.apache.catalina.startup.Catalina");  
  21.     Object startupInstance = startupClass.newInstance();  
  22.   
  23.     // Set the shared extensions class loader  
  24.     if (log.isDebugEnabled())  
  25.         log.debug("Setting startup class properties");  
  26.     String methodName = "setParentClassLoader";  
  27.     Class<?> paramTypes[] = new Class[1];  
  28.     paramTypes[0] = Class.forName("java.lang.ClassLoader");  
  29.     Object paramValues[] = new Object[1];  
  30.     paramValues[0] = sharedLoader;  
  31.     Method method =  
  32.         startupInstance.getClass().getMethod(methodName, paramTypes);  
  33.     method.invoke(startupInstance, paramValues);  
  34.   
  35.     catalinaDaemon = startupInstance;  
  36.   
  37. }  
1、设置catalina.home系统属性
如果catalina.home被设置过直接返回,否则设置:如果bootstrap.jar文件存在,就设置为这个文件所在目录的上一级目录;如果不存在就设置为当前工作目录。在%TOMCAT_HOME%\bin目录下实际上是有这个jar文件的,也就是catalina.home=%TOMCAT_HOME%。
2、设置catalina.base系统属性,和1差不多
3、initClassLoaders,初始化三个classLoader:
commonLoader:用于加载common/lib目录下的jar包和class文件
catalinaLoader:用于加载server/lib目录下的jar包和class文件
sharedLoader:用于加载shared/lib目录下的jar包和class文件
commonLoader是catalinaLoader和sharedLoader的parent classloader,Tomcat6以后,查看catalina.properties文件可以看见server.loader和shared.loader都是为空的。
catalina.properties文件中common.loader=${catalina.base}/lib,${catalina.base}/lib/*.jar,${catalina.home}/lib,${catalina.home}/lib/*.jar
4、然后设置当前线程的classloader为catalinaLoader
5、紧接着加载与安全相关的包和类
6、然后设置org.apache.catalina.startup.Catalina这个类的parent classloader为sharedLoader
7、创建org.apache.catalina.startup.Catalina这个类的实例并赋给catalinaDaemon
 

装配容器

通过调用org.apache.catalina.startup.Catalina的load方法来实现的
[html] view plaincopyprint?
 
  1. public void load() {  
  2.     initDirs();  
  3.     // Before digester - it may be needed  
  4.   
  5.     initNaming();  
  6.       
  7.     // Create and execute our Digester  
  8.     Digester digester = createStartDigester();  
  9.     digester.push(this);  
  10.     digester.parse(inputSource);  
  11.   
  12.     getServer().init();  
  13.     }  
  14. }  
1、初始化目录和命名规则,为digester解析XML做准备,digester准备后面再研究一下
2、创建一个digester对象,解析conf/server.xml文件,在解析server.xml的过程中会调用StandardService.setContainer方法,将其设置为StandardEngine
3、初始化Servlet窗口,这里的getServer()实际上返回的是StandardServer对象,这个初始化过程是在StandardServer类的initInternal方法中完成的,这个方法主要干了两件事,1是注册MBean,让JMX管理tomat容器,2是初始化Service
[html] view plaincopyprint?
 
  1. // Initialize our defined Services  
  2. for (int i = 0; i < services.length; i++) {  
  3.     services[i].init();  
  4. }  
从代码可以看出,一个tomcat容器是可以同时服务于多个应用的,tomcat配置多个services可以参考http://www.ff-bb.cn/logs/109466274.html service的初始化是在StandardService类的initInternal方法中完成的
[html] view plaincopyprint?
 
  1. protected void initInternal() throws LifecycleException {  
  2.         if (container != null) {  
  3.             container.init();  
  4.         }  
  5.   
  6.         // Initialize any Executors  
  7.         for (Executor executor : findExecutors()) {  
  8.             if (executor instanceof LifecycleMBeanBase) {  
  9.                 ((LifecycleMBeanBase) executor).setDomain(getDomain());  
  10.             }  
  11.             executor.init();  
  12.         }  
  13.   
  14.         // Initialize our defined Connectors  
  15.         synchronized (connectors) {  
  16.             for (Connector connector : connectors) {  
  17.                     connector.init();  
  18.             }  
  19.         }  
  20.     }  
这个方法也做了几件事,1是初始化container,会调用StandardEngine的initInternal方法,2初始化Executor,3是初始化两个连接器[Connector[HTTP/1.1-8080], Connector[AJP/1.3-8009]]
 

启动容器

此处的start调用的是org.apache.catalina.startup的start方法
[java] view plaincopyprint?
 
  1. public void start() {  
  2.     ...  
  3.     long t1 = System.nanoTime();  
  4.     // Start the new server  
  5.     try {  
  6.         getServer().start();  
  7.     } catch (LifecycleException e) {  
  8.         log.error("Catalina.start: ", e);  
  9.     }  
  10.     ...  
  11.     if (await) {  
  12.         await();  
  13.         stop();  
  14.     }  
  15. }  
start方法会调用StandardServer、StandardService、StandardEngine、StandardHost、StandardContext、StandardWrapper的start或者startInternal方法来完成启动过程,最后会循环等待,在关闭命令到来之前一直运行!
 

总结

1、tomcat中大量引入了模板方法模式,org.apache.catalina.util.LifecycleBase被所有容器继承,其中initInternal和startInternal方法是抽象方法,在初始化和启动时被每个容器会调用其init和start方法,这两个方法会去调用对应抽象方法***Internal,这些抽象方法都是在子类中实现的
2、tomcat中大量使用了类的反射,基本上都是通过配置文件获取类名,然后利用反射得到class对象,再通过newInstance获取对象。


 

(责任编辑:IT)
------分隔线----------------------------
栏目列表
推荐内容