浅析Tomcat之HostConfig

  • 来源:
  • 更新日期:2018-05-04

摘要:HostConfig主要承担虚拟主机启动是部署应用的作用.其中可以分解为3个类型的应用.在它的实现中主要分解为3个方法和内部类来解决.部署应用也就是动态在代码中生成Host的子容器Context.也就是一个app和一个Context对应. 我们知道deployApps这个方法把应用的部署分解到deployDescriptors,deployWARs,deployDirectories中.分别对应了

HostConfig主要承担虚拟主机启动是部署应用的作用.其中可以分解为3个类型的应用.在它的实现中主要分解为3个方法和内部类来解决.部署应用也就是动态在代码中生成Host的子容器Context.也就是一个app和一个Context对应. 我们知道deployApps这个方法把应用的部署分解到deployDescriptors,deployWARs,deployDirectories中.分别对应了3中形式的应用.那么我们先看下deployDescriptors

y2vzmvxcck4.jpg

/** * Deploy XML context descriptors. */ protected void deployDescriptors(File configBase, String[] files) { if (files == null) return; ExecutorService es = host.getStartStopExecutor(); List<Future<?>> results = new ArrayList<Future<?>>(); for (int i = 0; i < files.length; i++) { File contextXml = new File(configBase, files[i]); if (files[i].toLowerCase(Locale.ENGLISH).endsWith(".xml")) { ContextName cn = new ContextName(files[i]); if (isServiced(cn.getName()) || deploymentExists(cn.getName())) continue; results.add( es.submit(new DeployDescriptor(this, cn, contextXml))); } } for (Future<?> result : results) { try { result.get(); } catch (Exception e) { log.error(sm.getString( "hostConfig.deployDescriptor.threaded.error"), e); } } } 这个方法主要部署XML配置描述的应用.我们可以看到它和核心内容就是用ThreadPoolExecutor的submit方法来执行DeployDescriptor任务.也就是提交一个返回值的任务用于执行.其中的result.get()是处理任务中的异常.DeployDescriptor的run方法调用的是HostConfig的deployDescriptor方法.另外两种的应用部署方式跟这个是类似的.也是使用线程池来执行部署.

protected void deployDescriptor(ContextName cn, File contextXml) { DeployedApplication deployedApp = new DeployedApplication(cn.getName()); // Assume this is a configuration descriptor and deploy it if(log.isInfoEnabled()) { log.info(sm.getString("hostConfig.deployDescriptor", contextXml.getAbsolutePath())); } Context context = null; boolean isExternalWar = false; boolean isExternal = false; File expandedDocBase = null; try { synchronized (digester) { try { context = (Context) digester.parse(contextXml); } catch (Exception e) { log.error(sm.getString( "hostConfig.deployDescriptor.error", contextXml.getAbsolutePath())); context = new FailedContext(); } finally { digester.reset(); } } Class clazz = Class.forName(host.getConfigClass()); LifecycleListener listener = (LifecycleListener) clazz.newInstance(); context.addLifecycleListener(listener); context.setConfigFile(contextXml.toURI().toURL()); context.setName(cn.getName()); context.setPath(cn.getPath()); context.setWebappVersion(cn.getVersion()); // Add the associated docBase to the redeployed list if it\'s a WAR if (context.getDocBase() != null) { File docBase = new File(context.getDocBase()); if (!docBase.isAbsolute()) { docBase = new File(appBase(), context.getDocBase()); } // If external docBase, register .xml as redeploy first if (!docBase.getCanonicalPath().startsWith( appBase().getAbsolutePath() + File.separator)) { isExternal = true; deployedApp.redeployResources.put( contextXml.getAbsolutePath(), Long.valueOf(contextXml.lastModified())); deployedApp.redeployResources.put(docBase.getAbsolutePath(), Long.valueOf(docBase.lastModified())); if (docBase.getAbsolutePath().toLowerCase(Locale.ENGLISH).endsWith(".war")) { isExternalWar = true; } } else { log.warn(sm.getString("hostConfig.deployDescriptor.localDocBaseSpecified", docBase)); // Ignore specified docBase context.setDocBase(null); } } host.addChild(context); } catch (Throwable t) { ExceptionUtils.handleThrowable(t); log.error(sm.getString("hostConfig.deployDescriptor.error", contextXml.getAbsolutePath()), t); } finally { // Get paths for WAR and expanded WAR in appBase ....... } if (context != null && host.findChild(context.getName()) != null) { deployed.put(context.getName(), deployedApp); } } 上述就是在es.submit(new DeployDescriptor(this, cn, contextXml))中的线程中执行的方法.其大意主要也就是把解析出来的app转换成Tomcat中的Context做为Host的子容器.在另外的2个类型的部署应用方法deployWAR,deployDirectory所实现的也是类似的.只不过DeployDescriptor和deployWAR主要解析的是ApplicationContextXml也就是META-INF/context.xml,而deployDirectory主要解析的是ApplicationWebXml也就是/WEB-INF/web.xml其余大体上的流程是一致的.