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系统做了很多工作,下面我们详细分析一 ...
随机推荐
- DHCP命令执行CVE-2018-1111漏洞复现
DHCP命令执行_CVE-2018-1111漏洞复现 一.漏洞描述 在Red Hat Enterprise Linux多个版本的DHCP客户端软件包所包含的NetworkManager集成脚本中发现了 ...
- ZooKeeper 系列(三)—— Zookeeper常用 Shell 命令
一.节点增删改查 1.1 启动服务和连接服务 1.2 help命令 1.3 查看节点列表 1.4 新增节点 1.5 查看 ...
- lunix杂记_scp与vi编辑器
1.scp命令,复制其它服务器资源 scp 用户名@192.168.0.9:/usr/local/apache-tomcat-7.0.68 ./ scp -f username@192.168.0. ...
- 机器学习经典算法之Apriori
一. 搞懂关联规则中的几个概念 关联规则这个概念,最早是由 Agrawal 等人在 1993 年提出的.在 1994 年 Agrawal 等人又提出了基于关联规则的 Apriori 算法,至今 Apr ...
- 微服务-springboot打包
idea打包方式: 打包前确认项目可以正常运行 一.File->Project Structure->Artifacts->点击 + ->JAR->From module ...
- (ps2019)Photoshop 2019 最新破解版下载
Photoshop CC 2019新增功能: 下载地址 点我 新功能介绍:https://helpx.adobe.com/cn/photoshop/using/whats-new.html 经过改良设 ...
- Java学习笔记之---基础语法
Java学习笔记之---基础语法 一. Java中的命名规范 (一)包名 由多个单词组成时,所有字母小写(例如:onetwo) (二)类名和接口 由多个单词组成时,所有单词首字母大写(例如:OneTw ...
- STM32F0_HAL库驱动描述——LL驱动程序概述
LL驱动概述 低层(LL)驱动器旨在提供快速轻量级的专家导向层,它比硬件更接近硬件: 与HAL相反,LLAPI不适用于优化访问不是关键功能的外设设备,或者需要大量软件配置和/或复杂的高级堆栈(如USB ...
- hive merge into 批量更新测试
一.使用条件 hive2.2.0及之后的版本支持使用merge into 语法,使用源表数据批量目标表的数据.使用该功能还需做如下配置 1.参数配置 set hive.support.concurre ...
- 跨站脚本攻击(反射型xss)笔记(一)
环境:一个微信端(所以用浏览器演示UI有点变形) 下图是未插任何脚本时的原页面. 按惯例,上一波["><script>alert(1)</script>] 无弹 ...