浅析Tomcat之HostConfig

HostConfig主要承担虚拟主机启动是部署应用的作用.其中可以分解为3个类型的应用.在它的实现中主要分解为3个方法和内部类来解决.部署应用也就是动态在代码中生成Host的子容器Context.也就是一个app和一个Context对应.

我们知道deployApps这个方法把应用的部署分解到deployDescriptors,deployWARs,deployDirectories中.分别对应了3中形式的应用.那么我们先看下deployDescriptors

/**
 * 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其余大体上的流程是一致的.



留个爪印