设为首页 收藏本站
查看: 541|回复: 0

[经验分享] 浅析Tomcat之StandardContext

[复制链接]
发表于 2017-1-26 09:10:15 | 显示全部楼层 |阅读模式
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<SecurityRoleRef> 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中配置的内容.
 
首发于泛泛之辈 - http://www.lihongkun.com/archives/154

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-333527-1-1.html 上篇帖子: 学习tomcat 小记(4) 下篇帖子: Tomcat源码之JIoEndpoint
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表