05、Tomcat源码:catalina类

上一篇我们已经分析了Digester类,有基础分析Catalina类的代码,所以这篇主要是看下Catalina类,之前我们分析Bootstrap类的时候,知道Bootstrap的类主要是通过CatalinaClassLoader加载Catalina类调用Catalina的load(arguments), start(),stop(),stopServer(),现在我们逐个方法来看。

1、 load(arguments)方法:看源码load(arguments)最后调用的是load方法;

    1.1. load方法:

      看load方法之前先对比看server.xml和createStartDigester方法

      *

      createStartDigester方法server片段,

 1 long t1=System.currentTimeMillis();
 2         // Initialize the digester
 3         Digester digester = new Digester();
 4         digester.setValidating(false);
 5         digester.setRulesValidation(true);
 6         HashMap<Class<?>, List<String>> fakeAttributes = new HashMap<>();
 7         ArrayList<String> attrs = new ArrayList<>();
 8         attrs.add("className");
 9         fakeAttributes.put(Object.class, attrs);
10         digester.setFakeAttributes(fakeAttributes);
11         digester.setUseContextClassLoader(true);
12 
13         // Configure the actions we will be using
14         digester.addObjectCreate("Server",
15                                  "org.apache.catalina.core.StandardServer",
16                                  "className");
17         digester.addSetProperties("Server");
18         digester.addSetNext("Server",
19                             "setServer",
20                             "org.apache.catalina.Server");

可以看到我们之前分析的Rule,ObjectCreateRule,SetPropertiesRule,SetNextRule,当解析到的时候,会创建StandardServer,Push进Digester【ObjectCreateRule的作用】,设置的attribute到对应的StandardServer的setXXXX例如SetPort【SetPropertiesRule的作用】,会调用Catalina的方法setServer(StandardServer)【SetNextRule的作用】。这个时候Digester的内存结构是如下图

*

      下面看load方法代码片段,最后还是调用server.init。

      

 1 。。。。
 2 //根据System参数java.io.tmpdir判断临时文件夹
 3         initDirs();
 4 //
 5         initNaming();
 6 
 7         //创建startDigester,这个我们后面重点分析
 8         Digester digester = createStartDigester();
 9 
10         InputSource inputSource = null;
11         InputStream inputStream = null;
12         File file = null;
13         try {
14             try {
15 //默认是config/server.xml
16                 file = configFile();
17                 inputStream = new FileInputStream(file);
18                 inputSource = new InputSource(file.toURI().toURL().toString());
19             } catch (Exception e) {
20                 if (log.isDebugEnabled()) {
21                     log.debug(sm.getString("catalina.configFail", file), e);
22                 }
23             }
24             ……………
25 
26             try {
27                 inputSource.setByteStream(inputStream);
28 //将catalina,push进Digester
29                 digester.push(this);
30 //parse server.xml,解析过程中回调之前我们分析的rule
31                 digester.parse(inputSource);
32             } catch (SAXParseException spe) {
33                 log.warn("Catalina.start using " + getConfigFile() + ": " +
34                         spe.getMessage());
35                 return;
36             } catch (Exception e) {
37                 log.warn("Catalina.start using " + getConfigFile() + ": " , e);
38                 return;
39             }
40         } finally {
41             if (inputStream != null) {
42                 try {
43                     inputStream.close();
44                 } catch (IOException e) {
45                     // Ignore
46                 }
47             }
48         }
49 //parse之后catalina已经调用setServer方法创建得到server
50         getServer().setCatalina(this);
51         getServer().setCatalinaHome(Bootstrap.getCatalinaHomeFile());
52         getServer().setCatalinaBase(Bootstrap.getCatalinaBaseFile());
53 
54         // Stream redirection
55         initStreams();
56 
57         // Start the new server
58         try {
59 //调用server.init方法
60             getServer().init();
61         } catch (LifecycleException e) {
62             ……..
63         }

2、 start方法;

 1 ………
 2         
 3         try {
 4 //调用Server的start方法
 5             getServer().start();
 6         } catch (LifecycleException e) {
 7             ………
 8             return;
 9         }
10 
11         long t2 = System.nanoTime();
12         if(log.isInfoEnabled()) {
13             log.info("Server startup in " + ((t2 - t1) / 1000000) + " ms");
14         }
15 
16         //注册shutdownhook,jvm退出的时候会回调这个runnable
17         if (useShutdownHook) {
18             if (shutdownHook == null) {
19                 shutdownHook = new CatalinaShutdownHook();
20             }
21             Runtime.getRuntime().addShutdownHook(shutdownHook);
22 
23             ……….
24         }
25 
26         if (await) {
27             await();
28             stop();
29         }

3、 stopServer()方法;

 

 1 …….
 2 
 3         Server s = getServer();
 4         if (s == null) {
 5 //cmd 调用shutdown.bat的时候,走这里,当为空将创建StandServer 
 6             Digester digester = createStopDigester();
 7             File file = configFile();
 8             try (FileInputStream fis = new FileInputStream(file)) {
 9                 InputSource is =
10                     new InputSource(file.toURI().toURL().toString());
11                 is.setByteStream(fis);
12                 digester.push(this);
13                 digester.parse(is);
14             } catch (Exception e) {
15                 log.error("Catalina.stop: ", e);
16                 System.exit(1);
17             }
18         } else {
19             //不为空直接调用server stop,作为一个service运行的时候
20             try {
21                 s.stop();
22             } catch (LifecycleException e) {
23                 log.error("Catalina.stop: ", e);
24             }
25             return;
26         }
27 
28         s = getServer();
29         if (s.getPort()>0) {
30 //给监听ServerSocket,发送SHUTDOWN信息,关闭Server
31             try (Socket socket = new Socket(s.getAddress(), s.getPort());
32                     OutputStream stream = socket.getOutputStream()) {
33                 String shutdown = s.getShutdown();
34                 for (int i = 0; i < shutdown.length(); i++) {
35                     stream.write(shutdown.charAt(i));
36                 }
37                 stream.flush();
38             } catch (ConnectException ce) {
39                 log.error(sm.getString("catalina.stopServer.connectException",
40                                        s.getAddress(),
41                                        String.valueOf(s.getPort())));
42                 log.error("Catalina.stop: ", ce);
43                 System.exit(1);
44             } catch (IOException e) {
45                 log.error("Catalina.stop: ", e);
46                 System.exit(1);
47             }
48         } else {
49             log.error(sm.getString("catalina.stopServer"));
50             System.exit(1);
51         }

4、 Stop()方法;

 1 …………
 2         try {
 3             Server s = getServer();
 4             LifecycleState state = s.getState();
 5             if (LifecycleState.STOPPING_PREP.compareTo(state) <= 0
 6                     && LifecycleState.DESTROYED.compareTo(state) >= 0) {
 7                 //stop已经被调用
 8             } else {
 9 //调用server stop方法
10                 s.stop();
11                 s.destroy();
12             }
13         } catch (LifecycleException e) {
14             log.error("Catalina.stop", e);
15         }

总结:catalina类中,load方法调用的时候会将server.xml里面的配置信息通过Digester解析成对象,分析到目前为止可以知道的对象是Catalina->Server,start方法调用server.start同时注册shutdownHook,stopServer方法当双击ShutDown.bat来关闭tomcat的时候,将发送SHUTDOWN给正在运行的Server的ServerSocket,当tomcat作为一个service运行的时候,会直接调用Server的stop方法停止tomcat

版权声明:本文不是「本站」原创文章,版权归原作者所有 | 原文地址: