文档章节

浅析Tomcat之StandardContext

D_GrayMan
 D_GrayMan
发布于 2016/07/05 07:46
字数 1171
阅读 11
收藏 0
Context是Host的子容器,在servlet引擎中它代表了一个web application.它在每一个Catalina中部署的应用几乎都是存在的.它的子容器是Wrapper(一个具体servlet的定义),Context是标准实现是StandardContext,与StandardHost的实现模式类似.它承担了创建Wrapper容器(Servlet),Filter,ErrorPage等在web.xml中配置的内容. 首先构造函数总也是给pipeline添加一个StandardContextValve的基础阀.这个阀与前面介绍的2种不同的是它对用户访问的路径进行了限制.且看其invoke方法.
public final void invoke(Request request, Response response)  
    throws IOException, ServletException {  
  
    // Disallow any direct access to resources under WEB-INF or META-INF  
    MessageBytes requestPathMB = request.getRequestPathMB();  
    if ((requestPathMB.startsWithIgnoreCase("/META-INF/", 0))  
            || (requestPathMB.equalsIgnoreCase("/META-INF"))  
            || (requestPathMB.startsWithIgnoreCase("/WEB-INF/", 0))  
            || (requestPathMB.equalsIgnoreCase("/WEB-INF"))) {  
        response.sendError(HttpServletResponse.SC_NOT_FOUND);  
        return;  
    }  
  
    // Select the Wrapper to be used for this Request  
    Wrapper wrapper = request.getWrapper();  
    if (wrapper == null || wrapper.isUnavailable()) {  
        response.sendError(HttpServletResponse.SC_NOT_FOUND);  
        return;  
    }  
  
    //....(此处省略部分代码)  
  
    wrapper.getPipeline().getFirst().invoke(request, response);  
}
首先它会限制用户查询META-INF和WEB-INF中的内容,这也就是Tomcat中为何在url中无法访问这些路径中的内容的原因所在.接着它会找到具体的Wrapper,而调用其阀的方法.也就是把调用转发到具体的servlet了. 知道了Context的请求转发方式,下面看看它是如何创建子容器的,与HostConfig类似,有个ContextConfig类来侦听Conext的生命周期事件.对于StandardContext 所派发出的生命周期事件.lifecycleEvent根据不同侦听的事件类型来处理事件.其中的AFTER_INIT_EVENT事件 调用init方法,解析Context.xml,CONFIGURE_START_EVENT事件调用了configStart方法来初始化Context的一些配置,其中它调用了一个我们比较关心的方法是webConfig()函数,读取web.xml并且解析和创建了Context的子容器Wrapper,也就是Servlet.
Set<WebXml> defaults = new HashSet<WebXml>();
defaults.add(getDefaultWebXmlFragment());

WebXml webXml = createWebXml();

// Parse context level web.xml
InputSource contextWebXml = getContextWebXmlSource();
parseWebXml(contextWebXml, webXml, false);

ServletContext sContext = context.getServletContext();

// Ordering is important here

// Step 1. Identify all the JARs packaged with the application
// If the JARs have a web-fragment.xml it will be parsed at this
// point.
Map<String,WebXml> fragments = processJarsForWebFragments();

// Step 2. Order the fragments.
Set<WebXml> orderedFragments = null;
orderedFragments = WebXml.orderWebFragments(webXml, fragments);

// Step 3. Look for ServletContainerInitializer implementations
if (ok) {
	processServletContainerInitializers(orderedFragments);
}

if  (!webXml.isMetadataComplete() || typeInitializerMap.size() > 0) {
	// Step 4. Process /WEB-INF/classes for annotations
	if (ok) {
		......
	}

	// Step 5. Process JARs for annotations - only need to process
	// those fragments we are going to use
	if (ok) {
		processAnnotations(
				orderedFragments, webXml.isMetadataComplete());
	}

	// Cache, if used, is no longer required so clear it
	javaClassCache.clear();
}

if (!webXml.isMetadataComplete()) {
	// Step 6. Merge web-fragment.xml files into the main web.xml
	// file.
	if (ok) {
		ok = webXml.merge(orderedFragments);
	}

	// Step 7. Apply global defaults
	// Have to merge defaults before JSP conversion since defaults
	// provide JSP servlet definition.
	webXml.merge(defaults);

	// Step 8. Convert explicitly mentioned jsps to servlets
	if (ok) {
		convertJsps(webXml);
	}

	// Step 9. Apply merged web.xml to Context
	if (ok) {
		webXml.configureContext(context);
	}
} else {
	webXml.merge(defaults);
	convertJsps(webXml);
	webXml.configureContext(context);
}

// Step 9a. Make the merged web.xml available to other
// components, specifically Jasper, to save those components
// from having to re-generate it.
// TODO Use a ServletContainerInitializer for Jasper
String mergedWebXml = webXml.toXml();
sContext.setAttribute(
	   org.apache.tomcat.util.scan.Constants.MERGED_WEB_XML,
	   mergedWebXml);
if (context.getLogEffectiveWebXml()) {
	log.info("web.xml:\n" + mergedWebXml);
}

// Always need to look for static resources
// Step 10. Look for static resources packaged in JARs
if (ok) {
	.....
}

// Step 11. Apply the ServletContainerInitializer config to the
// context
if (ok) {
	.....
}
上述代码是webconfig函数,getDefaultWebXmlFragment取出了上层容器中的web.xml和web-fragment.xml这些是基础的配置.接着getContextWebXmlSource读取的是Context下面的web.xml也就是WEB-INF/web.xml,而parseWebXml对它进行了解析.所使用的是digester,具体的规则是WebRuleSet(有兴趣的可以仔细阅读),在此只是将解析好的web.xml转化为java形式的配置还没有进行Servlet实质上的创建和部署. processJarsForWebFragments把/WEB-INF/lib文件夹下的jar包读取一遍,查找其中的/META-INF/web-fragment.xml而WebXml.orderWebFragments(webXml, fragments)把其中需要进行执行的进行顺序排序.后面的步骤是比较多的,读者可自行阅读.这里重点看下step6前面的判断条件!webXml.isMetadataComplete()不成立的时候执行的是配置文件的合并.然后调用了webXml.configContext.此方法在实质上是执行Context配置文件中所配置的内容,也就是Wrapper子容器等的创建.这里主要看下Wrapper的配置内容.
for (ServletDef servlet : servlets.values()) {  
    Wrapper wrapper = context.createWrapper();  
    // Description is ignored  
    // Display name is ignored  
    // Icons are ignored  
  
    // jsp-file gets passed to the JSP Servlet as an init-param  
  
    if (servlet.getLoadOnStartup() != null) {  
        wrapper.setLoadOnStartup(servlet.getLoadOnStartup().intValue());  
    }  
    if (servlet.getEnabled() != null) {  
        wrapper.setEnabled(servlet.getEnabled().booleanValue());  
    }  
    wrapper.setName(servlet.getServletName());  
    Map<String,String> params = servlet.getParameterMap();  
    for (Entry<String, String> entry : params.entrySet()) {  
        wrapper.addInitParameter(entry.getKey(), entry.getValue());  
    }  
    wrapper.setRunAs(servlet.getRunAs());  
    Set roleRefs = servlet.getSecurityRoleRefs();  
    for (SecurityRoleRef roleRef : roleRefs) {  
        wrapper.addSecurityReference(  
                roleRef.getName(), roleRef.getLink());  
    }  
    wrapper.setServletClass(servlet.getServletClass());  
    MultipartDef multipartdef = servlet.getMultipartDef();  
    if (multipartdef != null) {  
        if (multipartdef.getMaxFileSize() != null &&  
                multipartdef.getMaxRequestSize()!= null &&  
                multipartdef.getFileSizeThreshold() != null) {  
            wrapper.setMultipartConfigElement(new MultipartConfigElement(  
                    multipartdef.getLocation(),  
                    Long.parseLong(multipartdef.getMaxFileSize()),  
                    Long.parseLong(multipartdef.getMaxRequestSize()),  
                    Integer.parseInt(  
                            multipartdef.getFileSizeThreshold())));  
        } else {  
            wrapper.setMultipartConfigElement(new MultipartConfigElement(  
                    multipartdef.getLocation()));  
        }  
    }  
    if (servlet.getAsyncSupported() != null) {  
        wrapper.setAsyncSupported(  
                servlet.getAsyncSupported().booleanValue());  
    }  
    wrapper.setOverridable(servlet.isOverridable());  
    context.addChild(wrapper);  
}
Servlet在配置文件解析后体现为ServletDef 类,里面存放了Servlet诸多属性.创建是通过wrapper来进行封装的.我们可以看到很都Servlet的属性都设置到其中,最后是context.addChild(wrapper)把创建好的wrapper作为context的子容器加入其中.configContext除了创建wrapper等还承担了创建Filter,ErrorPage等在web.xml中配置的内容.

© 著作权归作者所有

D_GrayMan
粉丝 0
博文 22
码字总数 18477
作品 0
深圳
高级程序员
私信 提问
tomcat部署后在web-inf下没有lib文件夹解决方案

我们在做web开发是,经常都要在eclipse中搭建web服务器,并将开发中的web项目部署到web服务器进行调试,在此,我选择的是tomcat服务器。之前部署web项目到tomcat进行启动调试都很正常,今天突...

minidai
2015/12/02
3.8K
0
Tomcat7 自动加载类及检测文件变动原理

在一般的web应用开发里通常会使用开发工具(如Eclipse、IntelJ)集成tomcat,这样可以将web工程项目直接发布到tomcat中,然后一键启动。经常遇到的一种情况是直接修改一个类的源文件,此时开...

JinHengyu
2017/11/16
1K
1
【死磕 Tomcat】—启动分析(四) webapp

原文作者:黄晓峰 原文链接:https://blog.csdn.net/dwademia/article/details/79328151 上一篇文章中我们分析了 Service、Engine、Host、Pipeline、Valve 组件的启动逻辑,在 HostConfig 中...

黄晓峰
2018/09/08
0
0
Eclipse启动Tomcat时报错:严重: Error configuring application listener of class

最近项目组让我开发两张简单的报表,用的是BIRT,只好从IDEA切换回Eclipse(Eclipse IDE for Java and Report Developers),用起来多少还是不太习惯。将项目部署到Tomcat并启动的时候,报了...

GreatQing
2016/09/13
1K
0
谈谈 Tomcat 架构及启动过程 [ 含部署 ]

(点击上方公众号,可快速关注) 来源:Rainstorm, github.com/c-rainstorm/blog/blob/master/tomcat/谈谈%20Tomcat%20架构及启动过程%5B含部署%5D.md 这个题目命的其实是很大的,写的时候还...

ImportNew
2018/01/10
0
0

没有更多内容

加载失败,请刷新页面

加载更多

Raspberry Pi 树莓派 搭建java8环境

更新软件源 apt-get upgradeapt-get update 移除自带的openjdk(如果有的话) apt-get remove openjdk* 安装oracle jdk,地址: https://www.oracle.com/technetwork/java/javase/downl......

ChangeZ
29分钟前
79
0
树莓派3b 安装openwrt

https://downloads.openwrt.org/releases/19.07.0/targets/brcm2708/bcm2710/openwrt-19.07.0-brcm2708-bcm2710-rpi-3-squashfs-factory.img.gz 插入并启动树莓派3B+,顺便接上键盘和显示器,......

FalconChen
49分钟前
71
0
OSChina 周一乱弹 —— 有些运动也常用到膝盖

Osc乱弹歌单(2020)请戳(这里) 【今日歌曲】 @薛定谔的兄弟 :分享洛神有语创建的歌单「我喜欢的音乐」: 《火宵の月・テーマ~ピアノソロ》- 中村由利子 手机党少年们想听歌,请使劲儿戳(...

小小编辑
今天
109
0
Redis持久化机制

RDB存储 RDB方式的持久化是通过快照完成的,当符合一定条件时Redis会自动将内存中的所有数据生成一份副本并存储在硬盘上。 Redis会在一下集中情况下对数据进行快照: 根据配置规则进行快照;...

XuePeng77
今天
81
0
float精度计算测试

package mainimport ("fmt""github.com/go-ozzo/ozzo-dbx"_ "github.com/go-sql-driver/mysql")type DecimalDemo struct {Id intAmount float64}func main() {db, _......

醉人的笑容你有没有
今天
127
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部