Tomcat8.5源码分析-HostConfig

来源:互联网 发布:json转map 编辑:程序博客网 时间:2024/05/16 18:16

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