context创建过程解析(二)之deployWARs
HostConfig.deployApps()
//在监听到start事件类型,也就是StandardHost调用startInternal
protected void deployApps() { File appBase = host.getAppBaseFile();
//这个值是在触发before_start时间时生成的,默认是tomcat安装目录+engine名+host名
File configBase = host.getConfigBaseFile();
//获取host上配置的webapp下的所有文件,默认是webapps目录下的所有文件
String[] filteredAppPaths = filterAppPaths(appBase.list());
// Deploy XML descriptors from configBase 发布xml描述文件
deployDescriptors(configBase, configBase.list());
// Deploy WARs
deployWARs(appBase, filteredAppPaths);
// Deploy expanded folders
deployDirectories(appBase, filteredAppPaths); } deployWARs protected void deployWARs(File appBase, String[] files) { if (files == null)
return; ExecutorService es = host.getStartStopExecutor();
List<Future<?>> results = new ArrayList<>(); for (int i = 0; i < files.length; i++) { if (files[i].equalsIgnoreCase("META-INF"))
continue;
if (files[i].equalsIgnoreCase("WEB-INF"))
continue;
File war = new File(appBase, files[i]);
//处理war
if (files[i].toLowerCase(Locale.ENGLISH).endsWith(".war") &&
war.isFile() && !invalidWars.contains(files[i]) ) { ContextName cn = new ContextName(files[i], true); if (isServiced(cn.getName())) {
continue;
}
//如果已经发布
if (deploymentExists(cn.getName())) {
DeployedApplication app = deployed.get(cn.getName());
boolean unpackWAR = unpackWARs;
if (unpackWAR && host.findChild(cn.getName()) instanceof StandardContext) {
unpackWAR = ((StandardContext) host.findChild(cn.getName())).getUnpackWAR();
}
//如果不需要解压,并且已经发布。那么判断对应的docBase是否已经存在
if (!unpackWAR && app != null) {
// Need to check for a directory that should not be
// there
File dir = new File(appBase, cn.getBaseName());
if (dir.exists()) {
if (!app.loggedDirWarning) {
log.warn(sm.getString(
"hostConfig.deployWar.hiddenDir",
dir.getAbsoluteFile(),
war.getAbsoluteFile()));
app.loggedDirWarning = true;
}
} else {
app.loggedDirWarning = false;
}
}
continue;
} // Check for WARs with /../ /./ or similar sequences in the name
if (!validateContextPath(appBase, cn.getBaseName())) {
log.error(sm.getString(
"hostConfig.illegalWarName", files[i]));
invalidWars.add(files[i]);
continue;
} results.add(es.submit(new DeployWar(this, cn, war)));
}
} for (Future<?> result : results) {
try {
result.get();
} catch (Exception e) {
log.error(sm.getString(
"hostConfig.deployWar.threaded.error"), e);
}
}
} HostConfig.deployWAR(cn, war); protected void deployWAR(ContextName cn, File war) { // Constants.ApplicationContextXml == META-INF/context.xml
File xml = new File(host.getAppBaseFile(),
cn.getBaseName() + "/" + Constants.ApplicationContextXml); File warTracker = new File(host.getAppBaseFile(), cn.getBaseName() + Constants.WarTracker); boolean xmlInWar = false;
try (JarFile jar = new JarFile(war)) {
JarEntry entry = jar.getJarEntry(Constants.ApplicationContextXml);
//判断是否有context.xml在jar包里面
if (entry != null) {
xmlInWar = true;
}
} catch (IOException e) {
/* Ignore */
} // If there is an expanded directory then any xml in that directory
// should only be used if the directory is not out of date and
// unpackWARs is true. Note the code below may apply further limits
boolean useXml = false;
// If the xml file exists then expandedDir must exists so no need to
// test that here
//如果对应xml存在,并且允许解压,也就是已经解压了,这个war包没有修改过
if (xml.exists() && unpackWARs &&
(!warTracker.exists() || warTracker.lastModified() == war.lastModified())) {
useXml = true;
} Context context = null;
//是否需要发布这个context.xml,通过校验
boolean deployThisXML = isDeployThisXML(war, cn); try {
//允许发布这个xml并且仅仅是使用xml并且不允许copyxml到配置目录,如果允许copy到配置目录,那么这个xml可能不是最新的。
if (deployThisXML && useXml && !copyXML) {
synchronized (digesterLock) {
try {
context = (Context) digester.parse(xml);
} catch (Exception e) {
log.error(sm.getString(
"hostConfig.deployDescriptor.error",
war.getAbsolutePath()), e);
} finally {
digester.reset();
if (context == null) {
context = new FailedContext();
}
}
}
//设置context.xml配置文件
context.setConfigFile(xml.toURI().toURL());
//允许发布这个context.xml并且这个xml在war包里面
} else if (deployThisXML && xmlInWar) {
synchronized (digesterLock) {
try (JarFile jar = new JarFile(war)) {
JarEntry entry = jar.getJarEntry(Constants.ApplicationContextXml);
try (InputStream istream = jar.getInputStream(entry)) {
context = (Context) digester.parse(istream);
}
} catch (Exception e) {
log.error(sm.getString(
"hostConfig.deployDescriptor.error",
war.getAbsolutePath()), e);
} finally {
digester.reset();
if (context == null) {
context = new FailedContext();
}
context.setConfigFile(
UriUtil.buildJarUrl(war, Constants.ApplicationContextXml));
}
}
//不允许发布这个context.xml并且这个xml在war包里面的,那么就直接new出一个StandardContext
} else if (!deployThisXML && xmlInWar) {
// Block deployment as META-INF/context.xml may contain security
// configuration necessary for a secure deployment.
log.error(sm.getString("hostConfig.deployDescriptor.blocked",
cn.getPath(), Constants.ApplicationContextXml,
new File(host.getConfigBaseFile(), cn.getBaseName() + ".xml")));
} else {
context = (Context) Class.forName(contextClass).getConstructor().newInstance();
}
} catch (Throwable t) {
ExceptionUtils.handleThrowable(t);
log.error(sm.getString("hostConfig.deployWar.error",
war.getAbsolutePath()), t);
} finally {
if (context == null) {
context = new FailedContext();
}
} boolean copyThisXml = false;//是否需要复制xml到配置文件夹中
if (deployThisXML) {//允许发布
if (host instanceof StandardHost) {
copyThisXml = ((StandardHost) host).isCopyXML();
} // If Host is using default value Context can override it. context指定的copyXml属性可以覆盖host级别的
if (!copyThisXml && context instanceof StandardContext) {
copyThisXml = ((StandardContext) context).getCopyXML();
}
//如果context.xml在war中,并且允许复制这个xml到配置路径,那么就将此context.xml复制到配置文件夹中
if (xmlInWar && copyThisXml) {
// Change location of XML file to config base
xml = new File(host.getConfigBaseFile(),
cn.getBaseName() + ".xml");
try (JarFile jar = new JarFile(war)) {
JarEntry entry = jar.getJarEntry(Constants.ApplicationContextXml);
try (InputStream istream = jar.getInputStream(entry);
FileOutputStream fos = new FileOutputStream(xml);
BufferedOutputStream ostream = new BufferedOutputStream(fos, 1024)) {
byte buffer[] = new byte[1024];
while (true) {
int n = istream.read(buffer);
if (n < 0) {
break;
}
ostream.write(buffer, 0, n);
}
ostream.flush();
}
} catch (IOException e) {
/* Ignore */
}
}
}
//下面这部分代码基本和deployDescriptors差不多
DeployedApplication deployedApp = new DeployedApplication(cn.getName(),
xml.exists() && deployThisXML && copyThisXml); long startTime = 0;
// Deploy the application in this WAR file
if(log.isInfoEnabled()) {
startTime = System.currentTimeMillis();
log.info(sm.getString("hostConfig.deployWar",
war.getAbsolutePath()));
} try {
// Populate redeploy resources with the WAR file
deployedApp.redeployResources.put
(war.getAbsolutePath(), Long.valueOf(war.lastModified())); if (deployThisXML && xml.exists() && copyThisXml) {
//这个xml被复制到配置目录
deployedApp.redeployResources.put(xml.getAbsolutePath(),
Long.valueOf(xml.lastModified()));
} else {
// In case an XML file is added to the config base later 如果配置加载配置目录中才会有效
deployedApp.redeployResources.put(
(new File(host.getConfigBaseFile(),
cn.getBaseName() + ".xml")).getAbsolutePath(),
Long.valueOf(0));
} Class<?> clazz = Class.forName(host.getConfigClass());
LifecycleListener listener = (LifecycleListener) clazz.getConstructor().newInstance();
context.addLifecycleListener(listener); context.setName(cn.getName());
context.setPath(cn.getPath());
context.setWebappVersion(cn.getVersion());
context.setDocBase(cn.getBaseName() + ".war");
host.addChild(context);//与deployDescriptors一样的操作
} catch (Throwable t) {
ExceptionUtils.handleThrowable(t);
log.error(sm.getString("hostConfig.deployWar.error",
war.getAbsolutePath()), t);
} finally {
// If we're unpacking WARs, the docBase will be mutated after
// starting the context
boolean unpackWAR = unpackWARs;
if (unpackWAR && context instanceof StandardContext) {
unpackWAR = ((StandardContext) context).getUnpackWAR();
}
//上面不是已经添加了docBase资源的监控了吗?这里是因为tomcat在解压了war之后会重新定义它的docBase目录,所以需要添加,不管原始的还是新的都要进行监控
if (unpackWAR && context.getDocBase() != null) {
File docBase = new File(host.getAppBaseFile(), cn.getBaseName());
deployedApp.redeployResources.put(docBase.getAbsolutePath(),
Long.valueOf(docBase.lastModified()));
addWatchedResources(deployedApp, docBase.getAbsolutePath(),
context);
if (deployThisXML && !copyThisXml && (xmlInWar || xml.exists())) {
deployedApp.redeployResources.put(xml.getAbsolutePath(),
Long.valueOf(xml.lastModified()));
}
} else {
// Passing null for docBase means that no resources will be
// watched. This will be logged at debug level.
addWatchedResources(deployedApp, null, context);
}
// Add the global redeploy resources (which are never deleted) at
// the end so they don't interfere with the deletion process
addGlobalRedeployResources(deployedApp);
} deployed.put(cn.getName(), deployedApp); if (log.isInfoEnabled()) {
log.info(sm.getString("hostConfig.deployWar.finished",
war.getAbsolutePath(), Long.valueOf(System.currentTimeMillis() - startTime)));
}
}
context创建过程解析(二)之deployWARs的更多相关文章
- context创建过程解析(一)之deployDescriptors
总结:主要是创建Context对象,并且将默认context配置,host级别配置,context配置的值设置进去,设置docBase,如果是war包就解压到webapp的目录中,重新设置docBas ...
- context创建过程解析(三)之deployDirectories
HostConfig.deployApps() //在监听到start事件类型,也就是StandardHost调用startInternal protected void deployApps() { ...
- Android深入理解Context(二)Activity和Service的Context创建过程
前言 上一篇文章我们学习了Context关联类和Application Context的创建过程,这一篇我们接着来学习Activity和Service的Context创建过程.需要注意的是,本篇的知识 ...
- Android深入理解Context(一)Context关联类和Application Context创建过程
前言 Context也就是上下文对象,是Android较为常用的类,但是对于Context,很多人都停留在会用的阶段,这个系列会带大家从源码角度来分析Context,从而更加深入的理解它. 1.Con ...
- ZooKeeper(三):请求处理链路的创建过程解析
我们知道,zk就是一个个处理链组成的. 但是,这些处理链是在什么创建的呢? ZooKeeper 中有三种角色的服务节点存在: Leader, Follower, Observer . 而每个服务节点的 ...
- Android Context创建过程
特定的资源或者类构成了Android应用程序的运行上下文环境 PackageManager, ClassLoader, Assert等等 Android应用程序窗口的运行上下文环境是通过Con ...
- InputSplit—>RecordReder—>map(key,value,context)的过程解析
上图首先描述了在TaskTracker端Task(MapTask.ReduceTask)的执行过程,MapTask(org.apache.hadoop.mapred)首先被TaskRunner调用,然 ...
- JVM系列(三):JVM创建过程解析
上两篇中梳理了整个java启动过程中,jvm大致是如何运行的.即厘清了我们认为的jvm的启动过程.但那里面仅为一些大致的东西,比如参数解析,验证,dll加载等等.把最核心的loadJavaVM()交给 ...
- [原创]Andorid DexClassLoader的创建过程解析(基于5.0)
做Android插件框架时,经常会用到dex的动态加载,就要直接或间接的使用DexClassLoader,在new DexClassLoader的时候Android系统做了很多工作,下面我们详细分析一 ...
随机推荐
- hgoi#20190517
T1-Mike and gcd problem Mike给定一个n个元素的整数序列,A=[a1,a2,...,an],每次操作可以选择一个i(1≤i<n),将a[i],a[i+1]变成a[i]- ...
- Spring cloud stream【消息分区】
在上篇文章中我们给大家介绍了Stream的消息分组,可以实现消息的重复消费的问题,但在某些场景下分组还不能满足我们的需求,比如,同时有多条同一个用户的数据,发送过来,我们需要根据用户统计,但是消息 ...
- python基础(1)--input print if else elif while 用法说明
1 变量名的命名规则: 由数字,字母和下划线组成,但是不能以数字开头命名变量.例如 a ,b ,c ,name ,user1 user_id 等都可作为变量名称. 1a,2b 3cd等都不行.特别注意 ...
- 【通过ssh oracle11g安装】centos6静默安装oracle11g
转载链接:https://blog.csdn.net/u011391839/article/details/76566316 根据实际情况略作调整~ 博主参考了以上链接成功进行安装,列一下自己遇到的坑 ...
- 【前端优化】js图片懒加载及优化
一.前言 为啥要对图片使用懒加载?我们首先来聊聊这个问题,对于页面来说架子啊速度影响着最大的就是图片,一张普通的图片可以达到4-5M的大小,而代码压缩也就只有几十KB.当页面图片过多的时候,页面加载速 ...
- .NET Core IdentityServer4实战 第Ⅴ章-单点登录
OiDc可以说是OAuth的改造版,在最初的OAuth中,我们需要先请求一下认证服务器获取下Access_token,然后根据Access_token去Get资源服务器, 况且OAuth1 和 2 完 ...
- Codeforces 758C:Unfair Poll(思维+模拟)
http://codeforces.com/problemset/problem/758/C 题意:教室里有n列m排,老师上课点名从第一列第一排开始往后点,直到点到第一列第m排,就从第二列第一排开始点 ...
- POI自动调整列宽支持中文
/** * @Description:表格自适应宽度(中文支持) * @Author: * @param sheet sheet * @param columnLength 列数 */ private ...
- ubuntu18.04上搭建KVM虚拟机环境超完整过程
看标题这是篇纯运维的文章.在中小型企业中,一般很少配置专业的运维人员,都是由开发人员兼着.同时,对有志于技术管理的开发人员来说,多了解一些运维及整个软件生命周期的知识,是很有帮助的,因为带团队不仅仅是 ...
- 如何正确使用Profibus插头以及终端电阻
插头与终端电阻在Profibus通讯中有着非常重要的作用,它们使用起来非常简单,没有很多复杂的设置:但是正是由于使用简单,使得很多工程师在使用当中忽略了一些细节,导致很多通讯问题. 1 Profibu ...