首页 > 编程语言 >SpringMVC父子容器加载与关系源码

SpringMVC父子容器加载与关系源码

时间:2022-12-21 12:03:52浏览次数:42  
标签:WebApplicationContext cwac parent SpringMVC servletContext 源码 context logger 加载


我们都知道SpringMVC父子容器加载是通过dispatcherServlet与ContextLoaderListener类:他们的关系源码如下:

先说父容器加载:Context'Loader'Listener源码如下:

@Override
public void contextInitialized(ServletContextEvent event) {
initWebApplicationContext(event.getServletContext());
}


public WebApplicationContext initWebApplicationContext(ServletContext servletContext) {
if (servletContext.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE) != null) {
throw new IllegalStateException(
"Cannot initialize context because there is already a root application context present - " +
"check whether you have multiple ContextLoader* definitions in your web.xml!");
}

Log logger = LogFactory.getLog(ContextLoader.class);
servletContext.log("Initializing Spring root WebApplicationContext");
if (logger.isInfoEnabled()) {
logger.info("Root WebApplicationContext: initialization started");
}
long startTime = System.currentTimeMillis();

try {
// Store context in local instance variable, to guarantee that
// it is available on ServletContext shutdown.
if (this.context == null) {
this.context = createWebApplicationContext(servletContext);
}
if (this.context instanceof ConfigurableWebApplicationContext) {
ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) this.context;
if (!cwac.isActive()) {
// The context has not yet been refreshed -> provide services such as
// setting the parent context, setting the application context id, etc
if (cwac.getParent() == null) {
// The context instance was injected without an explicit parent ->
// determine parent for root web application context, if any.
ApplicationContext parent = loadParentContext(servletContext);
cwac.setParent(parent);
}
configureAndRefreshWebApplicationContext(cwac, servletContext);
}
}
servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context);

加红这两行是重点,我们看到它把父容器加载的context放入了servletContext的一个属性中,这个属性的值如下:

String ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE = WebApplicationContext.class.getName() + ".ROOT";

后面我们看看DispatcherServlet的加载ApplicationContext的方式:


DispatcherServlet有一个父类是HttpServletBean进入它的init方法:

public final void init() throws ServletException {
if (logger.isDebugEnabled()) {
logger.debug("Initializing servlet '" + getServletName() + "'");
}

// Set bean properties from init parameters.
try {
PropertyValues pvs = new ServletConfigPropertyValues(getServletConfig(), this.requiredProperties);
BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(this);
ResourceLoader resourceLoader = new ServletContextResourceLoader(getServletContext());
bw.registerCustomEditor(Resource.class, new ResourceEditor(resourceLoader, this.environment));
initBeanWrapper(bw);
bw.setPropertyValues(pvs, true);
}
catch (BeansException ex) {
logger.error("Failed to set bean properties on servlet '" + getServletName() + "'", ex);
throw ex;
}

// Let subclasses do whatever initialization they like.
initServletBean();

if (logger.isDebugEnabled()) {
logger.debug("Servlet '" + getServletName() + "' configured successfully");
}
}
protected final void initServletBean() throws ServletException {
getServletContext().log("Initializing Spring FrameworkServlet '" + getServletName() + "'");
if (this.logger.isInfoEnabled()) {
this.logger.info("FrameworkServlet '" + getServletName() + "': initialization started");
}
long startTime = System.currentTimeMillis();

try {
this.webApplicationContext = initWebApplicationContext();
protected WebApplicationContext initWebApplicationContext() {
WebApplicationContext rootContext =
WebApplicationContextUtils.getWebApplicationContext(getServletContext());
WebApplicationContext wac = null;

if (this.webApplicationContext != null) {
// A context instance was injected at construction time -> use it
wac = this.webApplicationContext;
if (wac instanceof ConfigurableWebApplicationContext) {
ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) wac;
if (!cwac.isActive()) {
// The context has not yet been refreshed -> provide services such as
// setting the parent context, setting the application context id, etc
if (cwac.getParent() == null) {
// The context instance was injected without an explicit parent -> set
// the root application context (if any; may be null) as the parent
cwac.setParent(rootContext);
}
configureAndRefreshWebApplicationContext(cwac);
}
}
}


我们看到子容器里面放了rootContext父容器,那么这个父容器是不是就是ContextLoaderListener加载的context的呢,我们看下第一行标红的代码:

WebApplicationContext rootContext =
WebApplicationContextUtils.getWebApplicationContext(getServletContext());


public static WebApplicationContext getWebApplicationContext(ServletContext sc) {
return getWebApplicationContext(sc, WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE);
}
public interface WebApplicationContext extends ApplicationContext {
String ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE = WebApplicationContext.class.getName() + ".ROOT";


我们发现这个放入的值与我们ContextLoaderListener放入父容器中的值一样,说明子容器的rootContext就是我们之前放入的父容器。


标签:WebApplicationContext,cwac,parent,SpringMVC,servletContext,源码,context,logger,加载
From: https://blog.51cto.com/u_11970680/5959698

相关文章

  • AliMQ(RocketMQ)源码(一)创建producer
    公司现在在使用阿里云的AliMQ也就是RocketMQ,趁着工作之余,将RocketMQ的使用心得分析一下,关于RocketMQ的Producer、Consumer、Broker、NameServer等架构问题,在此处先不做分析......
  • AliMQ(RocketMQ)源码(二)producer.start()
    在创建完成Producer后,就进入了Producer的start()方法。start()方法DefaultMQProducerImpl的start()方法。this.serviceState=ServiceState.START_FAILED;......
  • 延迟加载
    一对一<resultMaptype="account"id="accountMap"><idcolumn="aid"property="id"/><resultcolumn="uid"property="uid"/><resultcolumn="mone......
  • 基于Spring+SpringMVC+Mybatis+Mysql在线考试系统
    @目录一、系统介绍二、功能展示1.用户登陆2.学生页面3.考试信息(老师)4.试卷库(老师)5.试题库(老师)6.考生信息(老师)7.成绩分析(老师)8.成绩排名(老师)9.错题统计(老师)10.成绩导出(老......
  • Dubbo架构设计与源码解析(二) 服务注册
    一、Dubbo简介Dubbo是一款典型的高扩展、高性能、高可用的RPC微服务框架,用于解决微服务架构下的服务治理与通信问题。其核心模块包含【RPC通信】和【服务治理】,其中......
  • pandas替换,加载,透视表
    pandas的级联和合并级联操作pd.concat,pd.appendpandas使用pd.concat函数,与np.concatenate函数类似,只是多了一些参数:objsaxis=0keysjoin='outer'/'inner':表示......
  • 万字长文 | Spring Cloud Alibaba组件之Nacos实战及Nacos客户端服务注册源码解析
    滴滴滴,上车了!本次旅途,你将获取到如下知识:Nacos在微服务架构中的作用Nacos在Linux下的安装与使用搭建真实项目环境,实现服务注册与发现真实项目环境下实现Nacos的配置......
  • 仿剪映播放器、剪辑视频、预览条、快速精准抽帧(附源码)
    给大家分享一下里面小伙伴的项目实践,高仿剪映快速抽帧、精准显示功能,而且还有源码给出!关于实现思路,之前也在公众号里面给大家分享过:​​干货|快速抽取缩略图是怎么练成的?......
  • 企业电子投票系统(论文+PPT+源码)
    设计题目 企业电子投票系统摘要目录​​第​​1部分概述1​第​​2部分 分析部分2​​2​​.1.功能需求2​第​​3部分 系统设计3​​3​​.1.功能模块设计3​​3​​.2.数......
  • 固定资产管理系统(论文+PPT+源码)
    固定资产管理系统摘要随着计算机信息技术的发展以及对资产、设备的管理科学化、合理化的高要求,利用计算机实现设备及资产的信息化管理已经显得非常重要。固定资产管理系统......