Tomcat学习之ContextConfig
2016-07-25 08:52
507 查看
http://blog.csdn.net/aesop_wubo/article/details/7922036
同HostConfig一样,ContextConfig也是在Digester解析server.xml的时候添加到StandardContext上的监听器,ContextConfig主要是处理web应用的配置文件,先看看它的init方法做了哪些事?
[java] view
plain copy
print?
protected void init() {
// Called from StandardContext.init()
Digester contextDigester = createContextDigester();
contextDigester.getParser();
if (log.isDebugEnabled())
log.debug(sm.getString("contextConfig.init"));
context.setConfigured(false);
ok = true;
contextConfig(contextDigester);
createWebXmlDigester(context.getXmlNamespaceAware(),
context.getXmlValidation());
try {
fixDocBase();
} catch (IOException e) {
log.error(sm.getString(
"contextConfig.fixDocBase", context.getName()), e);
}
}
1、处理Context的两个默认配置文件:conf/context.xml和/conf/[enginename]/[hostname]/context.xml.default,解析到context中;
2、对war包进行校验:主要是校验目录结构(是否有WEB-INF目录,是否有classes目录和META-INF目录等)
3、对于没有解压的文件还会将其解压:是在ExpandWar类的expand方法中完成的
[java] view
plain copy
print?
public static String expand(Host host, URL war, String pathname)
throws IOException {
...
// Expand the WAR into the new document base directory
JarURLConnection juc = (JarURLConnection) war.openConnection();
juc.setUseCaches(false);
JarFile jarFile = null;
InputStream input = null;
boolean success = false;
try {
jarFile = juc.getJarFile();
Enumeration<JarEntry> jarEntries = jarFile.entries();
while (jarEntries.hasMoreElements()) {
JarEntry jarEntry = jarEntries.nextElement();
String name = jarEntry.getName();
File expandedFile = new File(docBase, name);
if (!expandedFile.getCanonicalPath().startsWith(
canonicalDocBasePrefix)) {
//... throw exception
}
int last = name.lastIndexOf('/');
if (last >= 0) {
File parent = new File(docBase,
name.substring(0, last));
if (!parent.mkdirs() && !parent.isDirectory()) {
throw new IOException(
sm.getString("expandWar.createFailed", parent));
}
}
input = jarFile.getInputStream(jarEntry);
expand(input, expandedFile);
input.close();
} catch (IOException e) {
//
} finally {
//release resource
}
}
(1)、将war文件转换成jarEntries,并遍历
(2)、如果在webapps外直接抛异常
(3)、如果为目录,就在对应位置创建目录,否则就将文件读入input中,调用expand(input, expandedFile方法将文件内容copy到解压后的目录中
[java] view
plain copy
print?
private static void expand(InputStream input, File file)
throws IOException {
BufferedOutputStream output = null;
try {
output =
new BufferedOutputStream(new FileOutputStream(file));
byte buffer[] = new byte[2048];
while (true) {
int n = input.read(buffer);
if (n <= 0)
break;
output.write(buffer, 0, n);
}
} finally {
if (output != null) {
try {
output.close();
} catch (IOException e) {
// Ignore
}
}
}
}
就是一个IO操作,每次读取2k数据到文件中。
顺着生命周期,init后就应该是configureStart,configureStart方法中做的最重要的一件事就是配置web.xml文件,实现细节在webConfig中完成的:
1、扫描/META-INF/lib/目录下的jar文件,如果在META-INF下含有web-fragment.xml文件,解析它;
2、确定确定这些xml片段的顺序,servlet 3.0可以将配置文件分散在多个jar包里面,而且还可以定义这些配置文件的顺序。分为绝对顺序和相对顺序,绝对顺序是通过absolute-ordering标签定义的
<web-app>
<name>...</name>
<absolute-ordering>
<name>fragment1</name>
<name>fragment2</name>
</absolute-ordering>
</web-app>
还可以在web-fragment.xml里面通过before,after标签来定义这些配置文件的先后顺序,这里不再举例
这步主要是根据顺序,将这些配置文件加到集合orderedFragments中
3、处理ServletContainerInitializers的实现类,这也是servlet 3.0新增的特性,容器在启动时使用 JAR 服务 API(JAR Service API) 来发现 ServletContainerInitializer 的实现类,并且容器将 WEB-INF/lib 目录下 JAR 包中的类都交给该类的 onStartup() 方法处理,我们通常需要在该实现类上使用 @HandlesTypes 注解来指定希望被处理的类,过滤掉不希望给 onStartup() 处理的类。在onStartup方法中可以优先加载这些类,或者修改其中的方法等。这步主要是把这些类找到放到Set<ServletContainerInitializer>
scis中;
4、将应用中的web.xml与orderedFragments进行合并,合并在WebXml类的merge方法中实现
5、将应用中的web.xml与全局的web.xml文件(conf/web.xml和web.xml.default)进行合并
6、用合并好的WebXml来配置Context,这一步在处理servlet时,会为每个servlet创建一个wrapper,并调用addChild将每个wrapper作为context子容器,后续分析
下面简单了解一下WebXml的merge方法的实现,WebXml类是web.xml配置文件类,里面包含web.xml的所有标签,在它里面维护了这些标签的顺序,merge方法实现如下:
[java] view
plain copy
print?
public boolean merge(Set<WebXml> fragments) {
// As far as possible, process in alphabetical order so it is easy to
// check everything is present
// Merge rules vary from element to element. See SRV.8.2.3
WebXml temp = new WebXml();
for (WebXml fragment : fragments) {
if (!mergeMap(fragment.getContextParams(), contextParams,
temp.getContextParams(), fragment, "Context Parameter")) {
return false;
}
}
contextParams.putAll(temp.getContextParams());
...
}
[java] view
plain copy
print?
private static <T> boolean mergeMap(Map<String,T> fragmentMap,
Map<String,T> mainMap, Map<String,T> tempMap, WebXml fragment,
String mapName) {
for (Entry<String, T> entry : fragmentMap.entrySet()) {
final String key = entry.getKey();
if (!mainMap.containsKey(key)) {
// Not defined in main web.xml
T value = entry.getValue();
if (tempMap.containsKey(key)) {
if (value != null && !value.equals(
tempMap.get(key))) {
log.error(sm.getString(
"webXml.mergeConflictString",
mapName,
key,
fragment.getName(),
fragment.getURL()));
return false;
}
} else {
tempMap.put(key, value);
}
}
}
return true;
}
基本上每个标签都是按上面的例子合并的,简单说一下这个算法:
有两个map:mapA,mapB,要将mapA中有的在mapB中没有的元素加到mapB中,它的做法是遍历mapA,如果没有在mapB中就将其放入tmpMap中,循环完后mapB.putAll(tmpMap).
同HostConfig一样,ContextConfig也是在Digester解析server.xml的时候添加到StandardContext上的监听器,ContextConfig主要是处理web应用的配置文件,先看看它的init方法做了哪些事?
[java] view
plain copy
print?
protected void init() {
// Called from StandardContext.init()
Digester contextDigester = createContextDigester();
contextDigester.getParser();
if (log.isDebugEnabled())
log.debug(sm.getString("contextConfig.init"));
context.setConfigured(false);
ok = true;
contextConfig(contextDigester);
createWebXmlDigester(context.getXmlNamespaceAware(),
context.getXmlValidation());
try {
fixDocBase();
} catch (IOException e) {
log.error(sm.getString(
"contextConfig.fixDocBase", context.getName()), e);
}
}
1、处理Context的两个默认配置文件:conf/context.xml和/conf/[enginename]/[hostname]/context.xml.default,解析到context中;
2、对war包进行校验:主要是校验目录结构(是否有WEB-INF目录,是否有classes目录和META-INF目录等)
3、对于没有解压的文件还会将其解压:是在ExpandWar类的expand方法中完成的
[java] view
plain copy
print?
public static String expand(Host host, URL war, String pathname)
throws IOException {
...
// Expand the WAR into the new document base directory
JarURLConnection juc = (JarURLConnection) war.openConnection();
juc.setUseCaches(false);
JarFile jarFile = null;
InputStream input = null;
boolean success = false;
try {
jarFile = juc.getJarFile();
Enumeration<JarEntry> jarEntries = jarFile.entries();
while (jarEntries.hasMoreElements()) {
JarEntry jarEntry = jarEntries.nextElement();
String name = jarEntry.getName();
File expandedFile = new File(docBase, name);
if (!expandedFile.getCanonicalPath().startsWith(
canonicalDocBasePrefix)) {
//... throw exception
}
int last = name.lastIndexOf('/');
if (last >= 0) {
File parent = new File(docBase,
name.substring(0, last));
if (!parent.mkdirs() && !parent.isDirectory()) {
throw new IOException(
sm.getString("expandWar.createFailed", parent));
}
}
input = jarFile.getInputStream(jarEntry);
expand(input, expandedFile);
input.close();
} catch (IOException e) {
//
} finally {
//release resource
}
}
(1)、将war文件转换成jarEntries,并遍历
(2)、如果在webapps外直接抛异常
(3)、如果为目录,就在对应位置创建目录,否则就将文件读入input中,调用expand(input, expandedFile方法将文件内容copy到解压后的目录中
[java] view
plain copy
print?
private static void expand(InputStream input, File file)
throws IOException {
BufferedOutputStream output = null;
try {
output =
new BufferedOutputStream(new FileOutputStream(file));
byte buffer[] = new byte[2048];
while (true) {
int n = input.read(buffer);
if (n <= 0)
break;
output.write(buffer, 0, n);
}
} finally {
if (output != null) {
try {
output.close();
} catch (IOException e) {
// Ignore
}
}
}
}
就是一个IO操作,每次读取2k数据到文件中。
顺着生命周期,init后就应该是configureStart,configureStart方法中做的最重要的一件事就是配置web.xml文件,实现细节在webConfig中完成的:
1、扫描/META-INF/lib/目录下的jar文件,如果在META-INF下含有web-fragment.xml文件,解析它;
2、确定确定这些xml片段的顺序,servlet 3.0可以将配置文件分散在多个jar包里面,而且还可以定义这些配置文件的顺序。分为绝对顺序和相对顺序,绝对顺序是通过absolute-ordering标签定义的
<web-app>
<name>...</name>
<absolute-ordering>
<name>fragment1</name>
<name>fragment2</name>
</absolute-ordering>
</web-app>
还可以在web-fragment.xml里面通过before,after标签来定义这些配置文件的先后顺序,这里不再举例
这步主要是根据顺序,将这些配置文件加到集合orderedFragments中
3、处理ServletContainerInitializers的实现类,这也是servlet 3.0新增的特性,容器在启动时使用 JAR 服务 API(JAR Service API) 来发现 ServletContainerInitializer 的实现类,并且容器将 WEB-INF/lib 目录下 JAR 包中的类都交给该类的 onStartup() 方法处理,我们通常需要在该实现类上使用 @HandlesTypes 注解来指定希望被处理的类,过滤掉不希望给 onStartup() 处理的类。在onStartup方法中可以优先加载这些类,或者修改其中的方法等。这步主要是把这些类找到放到Set<ServletContainerInitializer>
scis中;
4、将应用中的web.xml与orderedFragments进行合并,合并在WebXml类的merge方法中实现
5、将应用中的web.xml与全局的web.xml文件(conf/web.xml和web.xml.default)进行合并
6、用合并好的WebXml来配置Context,这一步在处理servlet时,会为每个servlet创建一个wrapper,并调用addChild将每个wrapper作为context子容器,后续分析
下面简单了解一下WebXml的merge方法的实现,WebXml类是web.xml配置文件类,里面包含web.xml的所有标签,在它里面维护了这些标签的顺序,merge方法实现如下:
[java] view
plain copy
print?
public boolean merge(Set<WebXml> fragments) {
// As far as possible, process in alphabetical order so it is easy to
// check everything is present
// Merge rules vary from element to element. See SRV.8.2.3
WebXml temp = new WebXml();
for (WebXml fragment : fragments) {
if (!mergeMap(fragment.getContextParams(), contextParams,
temp.getContextParams(), fragment, "Context Parameter")) {
return false;
}
}
contextParams.putAll(temp.getContextParams());
...
}
[java] view
plain copy
print?
private static <T> boolean mergeMap(Map<String,T> fragmentMap,
Map<String,T> mainMap, Map<String,T> tempMap, WebXml fragment,
String mapName) {
for (Entry<String, T> entry : fragmentMap.entrySet()) {
final String key = entry.getKey();
if (!mainMap.containsKey(key)) {
// Not defined in main web.xml
T value = entry.getValue();
if (tempMap.containsKey(key)) {
if (value != null && !value.equals(
tempMap.get(key))) {
log.error(sm.getString(
"webXml.mergeConflictString",
mapName,
key,
fragment.getName(),
fragment.getURL()));
return false;
}
} else {
tempMap.put(key, value);
}
}
}
return true;
}
基本上每个标签都是按上面的例子合并的,简单说一下这个算法:
有两个map:mapA,mapB,要将mapA中有的在mapB中没有的元素加到mapB中,它的做法是遍历mapA,如果没有在mapB中就将其放入tmpMap中,循环完后mapB.putAll(tmpMap).
相关文章推荐
- java对世界各个时区(TimeZone)的通用转换处理方法(转载)
- java-注解annotation
- java-模拟tomcat服务器
- java-用HttpURLConnection发送Http请求.
- java-WEB中的监听器Lisener
- Android IPC进程间通讯机制
- i-jetty环境搭配与编译
- Android Native 绘图方法
- Android java 与 javascript互访(相互调用)的方法例子
- 实现单Tomcat多Server配置
- 生产环境下的Tomcat配置
- 介绍一款信息管理系统的开源框架---jeecg
- 聚类算法之kmeans算法java版本
- java实现 PageRank算法
- PropertyChangeListener简单理解
- Linux部署Tomcat服务器
- c++11 + SDL2 + ffmpeg +OpenAL + java = Android播放器