Tomcat8.5源码分析-HostConfig

HostConfig

1.  public void lifecycleEvent(LifecycleEvent event) {  
2.    
3.         // Identify the host we are associated with  
4.         try {  
5.             host = (Host) event.getLifecycle();  
6.             if (host instanceof StandardHost) {  
7.                 setCopyXML(((StandardHost) host).isCopyXML());  
8.                 setDeployXML(((StandardHost) host).isDeployXML());  
9.                 setUnpackWARs(((StandardHost) host).isUnpackWARs());  
10.                setContextClass(((StandardHost) host).getContextClass());  
11.            }  
12.        } catch (ClassCastException e) {  
13.            log.error(sm.getString("hostConfig.cce", event.getLifecycle()), e);  
14.            return;  
15.        }  
16.   
17.        // Process the event that has occurred  
18.        if (event.getType().equals(Lifecycle.PERIODIC_EVENT)) {  
19.            check();  
20.        } else if (event.getType().equals(Lifecycle.BEFORE_START_EVENT)) {  
21.            beforeStart();  
22.        } else if (event.getType().equals(Lifecycle.START_EVENT)) {  
23.            start();//StandHost.startInternal() 触发了这个事件  
24.        } else if (event.getType().equals(Lifecycle.STOP_EVENT)) {  
25.            stop();  
26.        }  
27.    }  

首先这个方法会检验Host是否是我们需要的,然后由于我们改变了生命周期的状态,所以调用它的start()方法。我们接着看代码:

1.  public void start() {  
2.      //进行日志的相关处理和jmx的注册  
3.         if (log.isDebugEnabled())  
4.             log.debug(sm.getString("hostConfig.start"));  
5.    
6.         try {  
7.             ObjectName hostON = host.getObjectName();  
8.             oname = new ObjectName  
9.                 (hostON.getDomain() + ":type=Deployer,host=" + host.getName());  
10.            Registry.getRegistry(null, null).registerComponent  
11.                (this, oname, this.getClass().getName());  
12.        } catch (Exception e) {  
13.            log.error(sm.getString("hostConfig.jmx.register", oname), e);  
14.        }  
15.   
16.        if (!host.getAppBaseFile().isDirectory()) {  
17.            log.error(sm.getString("hostConfig.appBase", host.getName(),  
18.                    host.getAppBaseFile().getPath()));  
19.            host.setDeployOnStartup(false);  
20.            host.setAutoDeploy(false);  
21.        }  
22.        /*部署应用*/  
23.        if (host.getDeployOnStartup())  
24.            deployApps();//context描述文件的部署,web目录的部署,WAR包的部署  
25.   
26.    }  

接着我们看deployApps():

1.  protected void deployApps() {  
2.    
3.         File appBase = host.getAppBaseFile();  
4.         File configBase = host.getConfigBaseFile();  
5.         String[] filteredAppPaths = filterAppPaths(appBase.list());  
6.         // Deploy XML descriptors from configBase  
7.         deployDescriptors(configBase, configBase.list());  
8.         // Deploy WARs  
9.         deployWARs(appBase, filteredAppPaths);  
10.        // Deploy expanded folders  
11.        deployDirectories(appBase, filteredAppPaths);  
12.   
13.    }  

我们只看这一个deployDescriptors描述文件的部署:

1.  protected void deployDescriptors(File configBase, String[] files) {  
2.    
3.         if (files == null)  
4.             return;  
5.    
6.         ExecutorService es = host.getStartStopExecutor();  
7.         List<Future<?>> results = new ArrayList<>();  
8.    
9.         for (int i = 0; i < files.length; i++) {/*扫描host配置文件的基础目录*/  
10.            File contextXml = new File(configBase, files[i]);  
11.   
12.            if (files[i].toLowerCase(Locale.ENGLISH).endsWith(".xml")) {/*对于每个配置文件*/  
13.                ContextName cn = new ContextName(files[i], true);  
14.   
15.                if (isServiced(cn.getName()) || deploymentExists(cn.getName()))  
16.                    continue;  
17.   
18.                results.add(  
19.                        es.submit(new DeployDescriptor(this, cn, contextXml)));/*由线程池完成解析部署,调用run()*/  
20.            }  
21.        }  
22.   
23.        for (Future<?> result : results) {  
24.            try {  
25.                result.get();  
26.            } catch (Exception e) {  
27.                log.error(sm.getString(  
28.                        "hostConfig.deployDescriptor.threaded.error"), e);  
29.            }  
30.        }  
31.    }  

接着看它的代码:

2.  private static class DeployDescriptor implements Runnable {  
2.    
3.         private HostConfig config;  
4.         private ContextName cn;  
5.         private File descriptor;  
6.    
7.         public DeployDescriptor(HostConfig config, ContextName cn,  
8.                 File descriptor) {  
9.             this.config = config;  
10.            this.cn = cn;  
11.            this.descriptor= descriptor;  
12.        }  
13.   
14.        @Override  
15.        public void run() {  
16.            config.deployDescriptor(cn, descriptor);/*线程调用方法*/  
17.        }  
18.    }  

继续看run方法:

1.  protected void deployDescriptor(ContextName cn, File contextXml) {  
2.    
3.      DeployedApplication deployedApp =  
4.              new DeployedApplication(cn.getName(), true);  
5.    
6.      long startTime = 0;  
7.      // Assume this is a configuration descriptor and deploy it  
8.      if(log.isInfoEnabled()) {  
9.         startTime = System.currentTimeMillis();  
10.        log.info(sm.getString("hostConfig.deployDescriptor",  
11.                 contextXml.getAbsolutePath()));  
12.     }  
13.   
14.     Context context = null;  
15.     boolean isExternalWar = false;  
16.     boolean isExternal = false;  
17.     File expandedDocBase = null;  
18.   
19.     try (FileInputStream fis = new FileInputStream(contextXml)) {  
20.         synchronized (digesterLock) {  
21.             try {  
22.                 context = (Context) digester.parse(fis);/*使用digester创建context实例*/  
23.             } catch (Exception e) {  
24.                 log.error(sm.getString(  
25.                         "hostConfig.deployDescriptor.error",  
26.                         contextXml.getAbsolutePath()), e);  
27.             } finally {  
28.                 digester.reset();  
29.                 if (context == null) {  
30.                     context = new FailedContext();  
31.                 }  
32.             }  
33.         }  

digster解析的时候创建了对象:

1.  Class<?> clazz = Class.forName(host.getConfigClass());  
2.             LifecycleListener listener =  
3.                 (LifecycleListener) clazz.newInstance();  
4.             context.addLifecycleListener(listener);//为context添加生命周期监听器  
5.    
6.             context.setConfigFile(contextXml.toURI().toURL());//设置context实例的ConfigFile  
7.             context.setName(cn.getName());//设置context实例的名称  
8.             context.setPath(cn.getPath());//设置context实例的路径  
9.             context.setWebappVersion(cn.getVersion());  
10.            //设置context实例的版本  
11.            // Add the associated docBase to the redeployed list if it's a WAR  
12.            if (context.getDocBase() != null) {  
13.                File docBase = new File(context.getDocBase());  
14.                if (!docBase.isAbsolute()) {  
15.                    docBase = new File(host.getAppBaseFile(), context.getDocBase());  
16.                }  
17.                // If external docBase, register .xml as redeploy first  
18.                if (!docBase.getCanonicalPath().startsWith(  
19.                        host.getAppBaseFile().getAbsolutePath() + File.separator)) {  
20.                    isExternal = true;  
21.                    deployedApp.redeployResources.put(  
22.                            contextXml.getAbsolutePath(),  
23.                            Long.valueOf(contextXml.lastModified()));  
24.                    deployedApp.redeployResources.put(docBase.getAbsolutePath(),  
25.                            Long.valueOf(docBase.lastModified()));  
26.                    if (docBase.getAbsolutePath().toLowerCase(Locale.ENGLISH).endsWith(".war")) {  
27.                        isExternalWar = true;  
28.                    }  
29.                } else {  
30.                    log.warn(sm.getString("hostConfig.deployDescriptor.localDocBaseSpecified",  
31.                             docBase));  
32.                    // Ignore specified docBase  
33.                    context.setDocBase(null);  
34.                }  
35.            }  
36.   
37.            host.addChild(context);//把context的实例添加到host  
38.        } catch (Throwable t) {  
39.            ExceptionUtils.handleThrowable(t);  
40.            log.error(sm.getString("hostConfig.deployDescriptor.error",  
41.                                   contextXml.getAbsolutePath()), t);  
42.        } finally {  
43.            // Get paths for WAR and expanded WAR in appBase  
44.         //获得WAR包的路径并且展开WAR包在appBase里面  
45.            // default to appBase dir + name  
46.            expandedDocBase = new File(host.getAppBaseFile(), cn.getBaseName());  
47.            if (context.getDocBase() != null  
48.                    && !context.getDocBase().toLowerCase(Locale.ENGLISH).endsWith(".war")) {  
49.                // first assume docBase is absolute  
50.             //先假定这个docBase的路径是绝对的  
51.                expandedDocBase = new File(context.getDocBase());  
52.                if (!expandedDocBase.isAbsolute()) {  
53.                    // if docBase specified and relative, it must be relative to appBase  
54.                 //如果路径是相对的,那么它一定是相对于appBase  
55.                    expandedDocBase = new File(host.getAppBaseFile(), context.getDocBase());  
56.                }  
57.            }  
58.   
59.            boolean unpackWAR = unpackWARs;  
60.            if (unpackWAR && context instanceof StandardContext) {  
61.                unpackWAR = ((StandardContext) context).getUnpackWAR();  
62.            }  
63.   
64.            // Add the eventual unpacked WAR and all the resources which will be  
65.            // watched inside it  
66.            //添加最终解开的WAR包  
67.            if (isExternalWar) {  
68.                if (unpackWAR) {  
69.                    deployedApp.redeployResources.put(expandedDocBase.getAbsolutePath(),  
70.                            Long.valueOf(expandedDocBase.lastModified()));  
71.                    addWatchedResources(deployedApp, expandedDocBase.getAbsolutePath(), context);  
72.                } else {  
73.                    addWatchedResources(deployedApp, null, context);  
74.                }  
75.            } else {  
76.                // Find an existing matching war and expanded folder  
77.             //找到已存在的匹配的war包并且展开文件夹  
78.                if (!isExternal) {  
79.                    File warDocBase = new File(expandedDocBase.getAbsolutePath() + ".war");  
80.                    if (warDocBase.exists()) {  
81.                        deployedApp.redeployResources.put(warDocBase.getAbsolutePath(),  
82.                                Long.valueOf(warDocBase.lastModified()));  
83.                    } else {  
84.                        // Trigger a redeploy if a WAR is added  
85.                     //触发再次解析如果WAR包被添加进去  
86.                        deployedApp.redeployResources.put(  
87.                                warDocBase.getAbsolutePath(),  
88.                                Long.valueOf(0));  
89.                    }  
90.                }  
91.                if (unpackWAR) {  
92.                    deployedApp.redeployResources.put(expandedDocBase.getAbsolutePath(),  
93.                            Long.valueOf(expandedDocBase.lastModified()));  
94.                    addWatchedResources(deployedApp,  
95.                            expandedDocBase.getAbsolutePath(), context);  
96.                } else {  
97.                    addWatchedResources(deployedApp, null, context);  
98.                }  
99.                if (!isExternal) {  
100.                       // For external docBases, the context.xml will have been  
101.                       // added above.  
102.                       deployedApp.redeployResources.put(  
103.                               contextXml.getAbsolutePath(),  
104.                               Long.valueOf(contextXml.lastModified()));  
105.                   }  
106.               }  
107.               // Add the global redeploy resources (which are never deleted) at  
108.               // the end so they don't interfere with the deletion process  
109.               addGlobalRedeployResources(deployedApp);  
110.           }  
111.      
112.           if (host.findChild(context.getName()) != null) {  
113.               deployed.put(context.getName(), deployedApp);  
114.           }  
115.      
116.           if (log.isInfoEnabled()) {  
117.               log.info(sm.getString("hostConfig.deployDescriptor.finished",  
118.                   contextXml.getAbsolutePath(), Long.valueOf(System.currentTimeMillis() - startTime)));  
119.           }  
120.       }  

再看这个方法:

1.  public void addChild(Container child) {  
2.    
3.          child.addLifecycleListener(new MemoryLeakTrackingListener());  
4.    
5.          if (!(child instanceof Context))  
6.              throw new IllegalArgumentException  
7.                  (sm.getString("standardHost.notContext"));  
8.          super.addChild(child);/*最终会调用child.start()方法,在containerBase里面*/  
9.    
10.     }  
再看super.addChild():
public void addChild(Container child) {  
2.      if (Globals.IS_SECURITY_ENABLED) {  
3.          PrivilegedAction<Void> dp =  
4.              new PrivilegedAddChild(child);  
5.          AccessController.doPrivileged(dp);  
6.      } else {  
7.          addChildInternal(child);  
8.      }  
9.  }  

其实不管怎么样都会调用addChildInternal(child),
继续看这个里面的代码:

1.  private void addChildInternal(Container child) {  
2.    
3.        if( log.isDebugEnabled() )  
4.            log.debug("Add child " + child + " " + this);  
5.        synchronized(children) {  
6.            if (children.get(child.getName()) != null)  
7.                throw new IllegalArgumentException("addChild:  Child name '" +  
8.                                                   child.getName() +  
9.                                                   "' is not unique");  
10.           child.setParent(this);  // May throw IAE  
11.           children.put(child.getName(), child);  
12.       }  
13.   
14.       // Start child  
15.       // Don't do this inside sync block - start can be a slow process and  
16.       // locking the children object can cause problems elsewhere  
17.       try {  
18.           if ((getState().isAvailable() ||  
19.                   LifecycleState.STARTING_PREP.equals(getState())) &&  
20.                   startChildren) {  
21.               child.start();/*在这个地方调用的*/  
22.           }  
23.       } catch (LifecycleException e) {  
24.           log.error("ContainerBase.addChild: start: ", e);  
25.           throw new IllegalStateException("ContainerBase.addChild: start: " + e);  
26.       } finally {  
27.           fireContainerEvent(ADD_CHILD_EVENT, child);  
28.       }  
29.   }  

可以看到最终child.start(),在这个地方终于转向了StandardContext,
其他两个部署方法省略,感兴趣可以查看相关资料。
Tomcat8.5源码分析-StandardContext

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值