欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 健康 > 美食 > 深入剖析Tomcat(十二) 详解StandardContext

深入剖析Tomcat(十二) 详解StandardContext

2024/10/24 22:19:36 来源:https://blog.csdn.net/weixin_37557894/article/details/139958469  浏览:    关键词:深入剖析Tomcat(十二) 详解StandardContext

StandardContext是Context容器的一个标准实现,一般情况下,Tomcat都是使用StandardContext类来创建Context容器。前面讲过,Context容器代表了一个Web应用,Tomcat本身支持部署多个应用,相应的每个应用都会有一个StandardContext实例来对应。在使用SpringBoot的前提下,一个Tomcat也就仅创建一个StandardContext实例,来服务这个SpringBoot框架对应的应用。

StandardContext既然针对的是一整个Web应用,那这个Web应用的功能就需要靠它来支撑起来,StandardContext通过一系列组件来实现它的功能。

载入器

Tomcat规定了每个Context容器都只加载自己应用下的类,不能加载该Tomcat下其他应用的类,所以,StandardContext持有一个“载入器(Loader)”对象,用来加载该应用程序下的所有类(servlet及相关类)。Loader的标准实现为WebappLoader。

重载

StandardContext中有一个reloadable属性,通过 setReloadable 方法可以设置它的值,如果设为true的话,证明该Context容器支持重载,Tomcat会安排一个后台线程不断地检查该Context关联的class及jar包的最后修改日期,如果发现有变化,就会重新加载该Context容器下的所有类。如果reloadable设为false,那么该Context容器不支持重载。

会话(session)

会话也是维护在Context这一层的,所以StandardContext中持有“会话管理器(Manager)”对象,来管理针对该Web应用的会话。Manager的标准实现为StandardManager,单个session的标准实现为StandardSession(实现了HttpSession接口)。session只在需要时才会创建,Tomcat会安排一个后台线程不断检查session对象有没有过期,如果过期了就将其失效。

子容器与映射器

一个Web应用程序一般来说会有多个servlet实例,一个servlet就对应一个Wrapper容器实例,所以一个Context实例下就会管理多个Wrapper实例,这些Wrapper实例称为Context的“子容器”。当Context接收到一个servlet请求后,需要知道该把这个请求具体交给哪个Wrapper来处理,这其间就需要有个映射关系了,将servlet的请求uri映射到具体的Wrapper上,StandardContext就持有一个“映射器(Mapper)”对象来实现这个映射逻辑。

StandardContext中维护了 servletMappings 与 children 两个map集合,通过这两个map,很容易就可以根据请求uri找到对应的Wrapper实例。

来看一下“映射器”是如何实现此映射逻辑的,StandardContextMapper是映射器的标准实现,其中的map方法就是通过request找Wrapper的方法,下面是缩减版的代码

public Container map(Request request, boolean update) {// 获取相对路径uri  (假设请求的资源路径为 /myapp/animal/tom, /myapp 代表部署在Tomcat中的应用名为myapp)String contextPath = ((HttpServletRequest) request.getRequest()).getContextPath();   //结果示例: “/myapp”String requestURI = ((HttpRequest) request).getDecodedRequestURI();                  //结果示例: “/myapp/animal/tom”String relativeURI = requestURI.substring(contextPath.length());                     //结果示例: “/animal/tom”Wrapper wrapper = null;if (!(relativeURI.equals("/")))name = context.findServletMapping(relativeURI);if (name != null)wrapper = (Wrapper) context.findChild(name);return wrapper;
}

上面映射器的逻辑是Tomcat4的逻辑,自Tomcat5之后,获取Wrapper的代码被放到了Request对象中,StandardContextMapper这个类也没有了,但是整体逻辑大致想通,明白思想即可。

start() 与 invoke()

上面列举了StandardContext中持有的比较重要的几个组件,各个组件也为StandardContext提供了相应的功能实现。而StandardContext具体应用这些组件的逻辑则主要集中在两个方法中:start()与invoke()。

start()方法是一个生命周期方法,Tomcat启动时会调用所有组件的start()方法,在StandardContext中,start()方法主要完成的功能是

  • 配置资源,识别到该Context容器对应的应用目录,将class及jar纳入自己的资源库中。
  • 创建各个组件实例,并调用各组件的start()方法完成组件的初始化。
  • 创建各个子容器(Wrapper)实例,并调用子容器的start()方法完成子容器的初始化。

start()方法主要是完成Context的一系列初始化操作,start()方法执行成功后,该StandardContext就可以对外工作了。

invoke()方法是StandardContext处理具体请求的方法,当一个servlet请求打进来后,就会进入到invoke()方法中,StandardContext#invoke()方法逻辑很简单,就是调用了一下它的Pipeline组件的invoke方法,其实真正对请求进行处理的对象是该Pipeline的基础阀:StandardContextValve。StandardContextValve#invoke() 方法会调用到映射器的map方法,根据请求uri找到指定Wrapper对象,然后调用Wrapper对象的invoke()方法,等Wrapper#invoke()方法执行结束后,StandardContext对本次servlet请求的处理也就基本完成了。(Wrapper#invoke()方法的逻辑请参考上一篇文章)。

在servlet的service方法中,如果有获取session的逻辑,那么StandardContext就会为其去寻找session,如果没有找到就会创建一个session给servlet用。具体逻辑可以参考第九篇文章。

StandardContext的基本逻辑就讲到这里,这篇文章串联了前些篇文章的知识,将StandardContext的完整脉络呈现了一下。下篇文章来研究下Host与Engine两种容器。

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com