tomct启动过程 bootstrap catalina

Tomcat中各个组件的生命周期是由server控制的。那么server的生命周期由谁控制呢? 

我们先来看下使用脚本启动tomcat的时候,首先会发生什么。

java应用要运行,需要一个main方法。tomcat启动的时候调用的是bootstrap中的main方法。

01 /**
02  * Main method, used for testing only.
03  *
04  * @param args Command line arguments to be processed
05  */
06 public static void main(String args[]) {
07  
08     if (daemon == null) {
09         // Don't set daemon until init() has completed
10         Bootstrap bootstrap = new Bootstrap();
11         try {
12             bootstrap.init();
13         catch (Throwable t) {
14             handleThrowable(t);
15             t.printStackTrace();
16             return;
17         }
18         daemon = bootstrap;
19     }
20  
21     try {
22         String command = "start";
23         if (args.length > 0) {
24             command = args[args.length - 1];
25         }
26  
27         if (command.equals("startd")) {
28             args[args.length - 1] = "start";
29             daemon.load(args);
30             daemon.start();
31         else if (command.equals("stopd")) {
32             args[args.length - 1] = "stop";
33             daemon.stop();
34         else if (command.equals("start")) {
35             daemon.setAwait(true);
36             daemon.load(args);
37             daemon.start();
38         else if (command.equals("stop")) {
39             daemon.stopServer(args);
40         else if (command.equals("configtest")) {
41             daemon.load(args);
42             if (null==daemon.getServer()) {
43                 System.exit(1);
44             }
45             System.exit(0);
46         else {
47             log.warn("Bootstrap: command \"" + command + "\" does not exist.");
48         }
49     catch (Throwable t) {
50         // Unwrap the Exception for clearer error reporting
51         if (t instanceof InvocationTargetException &&
52                 t.getCause() != null) {
53             t = t.getCause();
54         }
55         handleThrowable(t);
56         t.printStackTrace();
57         System.exit(1);
58     }
59  
60 }
这个main方法首先会new一个Bootstrap对象,并且把这个对象放到一个static域中。 
然后会对这个对象进行初始化,初始化方法如下: 
01 /**
02  * Initialize daemon.
03  */
04 public void init()
05     throws Exception
06 {
07  
08     // Set Catalina path
09     setCatalinaHome();
10     setCatalinaBase();
11  
12     initClassLoaders();
13  
14     Thread.currentThread().setContextClassLoader(catalinaLoader);
15  
16     SecurityClassLoad.securityClassLoad(catalinaLoader);
17  
18     // Load our startup class and call its process() method
19     if (log.isDebugEnabled())
20         log.debug("Loading startup class");
21     Class<?> startupClass =
22         catalinaLoader.loadClass
23         ("org.apache.catalina.startup.Catalina");
24     Object startupInstance = startupClass.newInstance();
25  
26     // Set the shared extensions class loader
27     if (log.isDebugEnabled())
28         log.debug("Setting startup class properties");
29     String methodName = "setParentClassLoader";
30     Class<?> paramTypes[] = new Class[1];
31     paramTypes[0] = Class.forName("java.lang.ClassLoader");
32     Object paramValues[] = new Object[1];
33     paramValues[0] = sharedLoader;
34     Method method =
35         startupInstance.getClass().getMethod(methodName, paramTypes);
36     method.invoke(startupInstance, paramValues);
37  
38     catalinaDaemon = startupInstance;
39  
40 }

在这个init方法中,会new一个catalina对象。bootstrap的大多数操作,诸如start、stop、load等,实际上都是调用的这个catalina对象的相应方法。


在bootstrap的初始化完成之后,会根据用户输入的main函数的参数(start、stop等),判断执行什么操作。
如果是start参数,就表明是启动tomcat。会先后执行daemon.setAwait、daemon.load、daemon.start这三个方法。他们最终会分别采用反射的方式去调用之前已经初始化的catalina的对应方法setAwait、load、start。也就是说其实bootstrap就调用了catalina的方法,本身是没做什么额外动作的。
stop则表明是关闭tomcat。

1 /**
2  * Daemon object used by main.
3  */
4 private static Bootstrap daemon = null;

这里需要注意一点,我们使用脚本启动和关闭tomcat的时候,实际上最终都是执行bootstrap的main方法,正因为daemon是static的,所以,我们start和stop的时候,实际上操作的是同一个bootstrap对象,才能对同一个tomcat的启动和关闭。 

如上面所说,在启动过程中,daemon.load会调用catalina的load方法。catalina的load方法如下:

001 /**
002  * Start a new server instance.
003  */
004 public void load() {
005  
006     long t1 = System.nanoTime();
007  
008     initDirs();
009  
010     // Before digester - it may be needed
011  
012     initNaming();
013  
014     // Create and execute our Digester
015     Digester digester = createStartDigester();
016  
017     InputSource inputSource = null;
018     InputStream inputStream = null;
019     File file = null;
020     try {
021         file = configFile();
022         inputStream = new FileInputStream(file);
023         inputSource = new InputSource("file://" + file.getAbsolutePath());
024     catch (Exception e) {
025         if (log.isDebugEnabled()) {
026             log.debug(sm.getString("catalina.configFail", file), e);
027         }
028     }
029     if (inputStream == null) {
030         try {
031             inputStream = getClass().getClassLoader()
032                 .getResourceAsStream(getConfigFile());
033             inputSource = new InputSource
034                 (getClass().getClassLoader()
035                  .getResource(getConfigFile()).toString());
036         catch (Exception e) {
037             if (log.isDebugEnabled()) {
038                 log.debug(sm.getString("catalina.configFail",
039                         getConfigFile()), e);
040             }
041         }
042     }
043  
044     // This should be included in catalina.jar
045     // Alternative: don't bother with xml, just create it manually.
046     if( inputStream==null ) {
047         try {
048             inputStream = getClass().getClassLoader()
049                     .getResourceAsStream("server-embed.xml");
050             inputSource = new InputSource
051             (getClass().getClassLoader()
052                     .getResource("server-embed.xml").toString());
053         catch (Exception e) {
054             if (log.isDebugEnabled()) {
055                 log.debug(sm.getString("catalina.configFail",
056                         "server-embed.xml"), e);
057             }
058         }
059     }
060  
061  
062     if (inputStream == null || inputSource == null) {
063         if  (file == null) {
064             log.warn(sm.getString("catalina.configFail",
065                     getConfigFile() + "] or [server-embed.xml]"));
066         else {
067             log.warn(sm.getString("catalina.configFail",
068                     file.getAbsolutePath()));
069             if (file.exists() && !file.canRead()) {
070                 log.warn("Permissions incorrect, read permission is not allowed on the file.");
071             }
072         }
073         return;
074     }
075  
076     try {
077         inputSource.setByteStream(inputStream);
078         digester.push(this);
079         digester.parse(inputSource);
080     catch (SAXParseException spe) {
081         log.warn("Catalina.start using " + getConfigFile() + ": " +
082                 spe.getMessage());
083         return;
084     catch (Exception e) {
085         log.warn("Catalina.start using " + getConfigFile() + ": " , e);
086         return;
087     finally {
088         try {
089             inputStream.close();
090         catch (IOException e) {
091             // Ignore
092         }
093     }
094  
095     getServer().setCatalina(this);
096  
097     // Stream redirection
098     initStreams();
099  
100     // Start the new server
101     try {
102         getServer().init();
103     catch (LifecycleException e) {
104         if (Boolean.getBoolean("org.apache.catalina.startup.EXIT_ON_INIT_FAILURE")) {
105             throw new java.lang.Error(e);
106         else {
107             log.error("Catalina.start", e);
108         }
109  
110     }
111  
112     long t2 = System.nanoTime();
113     if(log.isInfoEnabled()) {
114         log.info("Initialization processed in " + ((t2 - t1) / 1000000) + " ms");
115     }
116  
117 }

这个方法实际上是在加载、解析server.xml,生成tomcat的组件:server、service、connector、engine、host、context等。最后调用server的init方法。 
我们之前提到过tomcat中server用来管理整个tomcat的生命周期

daemon.load方法执行之后,会执行daemon.start,这个方法调用catalina的start方法,catalina调用server的start方法,从而启动tomcat的各个组件。

01 /**
02  * Start a new server instance.
03  */
04 public void start() {
05  
06     if (getServer() == null) {
07         load();
08     }
09  
10     if (getServer() == null) {
11         log.fatal("Cannot start server. Server instance is not configured.");
12         return;
13     }
14  
15     long t1 = System.nanoTime();
16  
17     // Start the new server
18     try {
19         getServer().start();
20     catch (LifecycleException e) {
21         log.error("Catalina.start: ", e);
22     }
23  
24     long t2 = System.nanoTime();
25     if(log.isInfoEnabled()) {
26         log.info("Server startup in " + ((t2 - t1) / 1000000) + " ms");
27     }
28  
29     // Register shutdown hook
30     if (useShutdownHook) {
31         if (shutdownHook == null) {
32             shutdownHook = new CatalinaShutdownHook();
33         }
34         Runtime.getRuntime().addShutdownHook(shutdownHook);
35  
36         // If JULI is being used, disable JULI's shutdown hook since
37         // shutdown hooks run in parallel and log messages may be lost
38         // if JULI's hook completes before the CatalinaShutdownHook()
39         LogManager logManager = LogManager.getLogManager();
40         if (logManager instanceof ClassLoaderLogManager) {
41             ((ClassLoaderLogManager) logManager).setUseShutdownHook(
42                     false);
43         }
44     }
45  
46     if (await) {
47         await();
48         stop();
49     }
50 }


server start之后,catalina会创建一个 CatalinaShutdownHook 对象,然后将它添加到运行时的shutdownHook中。即注册一个虚拟机的shutdown hook,这样在我们不通过脚本关闭tomcat,而是直接杀死进程的时候,也能够执行catalina的stop方法,完成tomcat的关闭过程。 
01 /**
02  * Shutdown hook which will perform a clean shutdown of Catalina if needed.
03  */
04 protected class CatalinaShutdownHook extends Thread {
05  
06     @Override
07     public void run() {
08         try {
09             if (getServer() != null) {
10                 Catalina.this.stop();
11             }
12         catch (Throwable ex) {
13             ExceptionUtils.handleThrowable(ex);
14             log.error(sm.getString("catalina.shutdownHookFail"), ex);
15         finally {
16             // If JULI is used, shut JULI down *after* the server shuts down
17             // so log messages aren't lost
18             LogManager logManager = LogManager.getLogManager();
19             if (logManager instanceof ClassLoaderLogManager) {
20                 ((ClassLoaderLogManager) logManager).shutdown();
21             }
22         }
23     }
24 }

The Java virtual machine shuts down in response to two kinds of events:
1、程序正常退出,包括最后一个non-daemon线程退出或者Runtime.exit、System.exit方法被调用。 
2、java虚拟机被终止,包括被用户中断,如:^C,或者系统级的事件:用户登出、系统关闭等。 
发生上面的情况的时候,虚拟机就会调用所有的shutdown hook。 

综上,tomcat启动过程实际就是bootstrap调用catalina的start方法,然后catalina调用server的start方法。关闭的时候,可以是bootstrap的stop方法调用catalina的stop方法,也可以是Hook调用catalina的stop方法,然后catalina的stop方法调用server的stop方法。
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值