|
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);
if (files.toLowerCase(Locale.ENGLISH).endsWith(".xml")) {
ContextName cn = new ContextName(files);
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其余大体上的流程是一致的.
首发于泛泛之辈 - http://www.lihongkun.com/archives/152 |
|
|