Spring-web源码解析之ContextLoader

简介: 基于版本4.1.7.RELEASE ContextLoader :应用root application context初始化的实际执行着,被ContextLoaderListener调用...

基于版本4.1.7.RELEASE

ContextLoader应用root application context初始化的实际执行着,被ContextLoaderListener调用

构造函数:

public ContextLoader() {
}

根据servlet配置中的contextClass和contextConfigLocation来创建web application context,在其子类ContextLoaderListener被申明的时候会调用默认的构造函数。

带参数的构造函数:

public ContextLoader(WebApplicationContext context) {
   this.context = context;
}

context作用同ContextLoaderListener中说明一样,只是ContextLoaderListener调用super(context)的时候会调用到此方法中,然后将context赋值给类属性,查看类属性的申明:

/**
 * The root WebApplicationContext instance that this loader manages.
 */
private WebApplicationContext context;

即可明白通过构造函数设置的是root WebApplicationContext

下面来看在ContextLoaderListener的初始化事件通知中所调用的initWebApplicationContext方法

/**
 * 通过参数servletContext初始化WebApplicationContext,使用构造时提供的WebApplicationContext或者根据contextClass和contextConfigL * ocation(在web.xml定义)创建一个新的WebApplicationContext
 */
public WebApplicationContext initWebApplicationContext(ServletContext servletContext) {
   //防止重复初始化
   if (servletContext.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE) != null) {
      throw new IllegalStateException;
   }

   try {
      //如果当前的rootWebApplicationContext为空 则创建一个,如果不为空有可能是构造时传进来的
      if (this.context == null) {
         this.context = createWebApplicationContext(servletContext);
      }
      if (this.context instanceof ConfigurableWebApplicationContext) {
         ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) this.context;
	//判断是否active的条件是,至少被refresh了1次并且没有被关闭。refresh可以理解为同步配置数据
         if (!cwac.isActive()) {
            // context没有被refresh
            if (cwac.getParent() == null) {
               // context没有明确的父容器 读取父容器
               ApplicationContext parent = loadParentContext(servletContext);
               cwac.setParent(parent);
            }
	    //配置和刷新context
            configureAndRefreshWebApplicationContext(cwac, servletContext);
         }
      }
      //将context保存到WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE
      servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context);
      //这里根据classloader来判断当前线程是否是加载ContextLoader的线程。
      ClassLoader ccl = Thread.currentThread().getContextClassLoader();
      if (ccl == ContextLoader.class.getClassLoader()) {
         currentContext = this.context;
      }
      else if (ccl != null) {
         currentContextPerThread.put(ccl, this.context);
      }
      return this.context;
   }
   catch (RuntimeException ex) {
   }
   catch (Error err) {
   }
}

这里有几个疑问,parent是什么,还有线程和context的对应关系是用来做什么的?

对于parent可以看loadParentContext这个方法:

protected ApplicationContext loadParentContext(ServletContext servletContext) {
   ApplicationContext parentContext = null;
   //获取web.xml配置文件中指定的locatorFactorySelector,如果没有配置这个选项,默认指向“class path*:beanRefContext.xml”
   String locatorFactorySelector = servletContext.getInitParameter(LOCATOR_FACTORY_SELECTOR_PARAM);
   //获取web.xml配置文件中指定的parentContentKey,这个key指向一个被加载完成的BeanFactory
   String parentContextKey = servletContext.getInitParameter(LOCATOR_FACTORY_KEY_PARAM);

   if (parentContextKey != null) {
      //获取beanFactory定位器
      BeanFactoryLocator locator = ContextSingletonBeanFactoryLocator.getInstance(locatorFactorySelector);
      //根据定位器查找到指定的BeanFactory,该beanFactory加载了beanRefContext.xml(默认情况下),在设置配置文件路径完成后调用了自身的refresh,所以已经将配置文件中定义的内容加载完成了,而完成加载的ApplicationContext就是这里要返回的parentContext
      this.parentContextRef = locator.useBeanFactory(parentContextKey);
      parentContext = (ApplicationContext) this.parentContextRef.getFactory();
   }

   return parentContext;
}

这个方法一般是在EJB或者EAR需要共享容器的时候使用,对于一般的WEB型应用,由于不配置locatorFactorySelector,所以这个方法实际上并没有运行。


线程和context的对应关系存放在currentContextPerThread中,该变量的类型是Map<ClassLoader,WebApplicationContext>,至于为什么这么存,

在closeWebApplicationContext中我们可以一窥端倪

public void closeWebApplicationContext(ServletContext servletContext) {
   try {
//关闭当前的Context,关闭过程中会产生关闭事件通知,销毁当前Context关联的bean和beanFactory,回调子类的onClose方法,active设置成false。
      if (this.context instanceof ConfigurableWebApplicationContext) {
         ((ConfigurableWebApplicationContext) this.context).close();
      }
   }
   finally {
      ClassLoader ccl = Thread.currentThread().getContextClassLoader();
//释放ClassLoader和Context对应列表中当前ClassLoader对应的Context
      if (ccl == ContextLoader.class.getClassLoader()) {
         currentContext = null;
      }
      else if (ccl != null) {
         currentContextPerThread.remove(ccl);
      }
      servletContext.removeAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE);
      if (this.parentContextRef != null) {
//释放对parent的引用
         this.parentContextRef.release();
      }
   }
}

currentContextPerThread是一个静态类型的引用,目的就是保存不同的ClassLoader对应的Context以防止在销毁Context时出现错误关闭的情况。



在上面的处理过程中,configureAndRefreshWebApplicationContext做了以下几件事

1 设置ID,把ServletContext中的ID赋值给WebApplicationContext,如果没有,则设置默认值

2 根据contextConfigLocation参数(web.xml)指定的地址,找到spring application的xml文件

3 初始化环境变量

4 根据定制的ApplicationContextInitializer初始化Context,这些定制器必须实现ApplicationContextInitializer  并且在contextInitializerClasses(web.xml)申明出来

5 刷新调用refresh方法

由此我们可以看出,如果要对容器做定制化修改,根据第四步来编写自定义类即可。

那么,走到这里,整个初始化就剩下refresh了,refresh里面做的事情非常多,下一节再讲



目录
相关文章
|
6天前
|
Java 关系型数据库 MySQL
一套java+ spring boot与vue+ mysql技术开发的UWB高精度工厂人员定位全套系统源码有应用案例
UWB (ULTRA WIDE BAND, UWB) 技术是一种无线载波通讯技术,它不采用正弦载波,而是利用纳秒级的非正弦波窄脉冲传输数据,因此其所占的频谱范围很宽。一套UWB精确定位系统,最高定位精度可达10cm,具有高精度,高动态,高容量,低功耗的应用。
一套java+ spring boot与vue+ mysql技术开发的UWB高精度工厂人员定位全套系统源码有应用案例
|
8天前
yolo-world 源码解析(六)(2)
yolo-world 源码解析(六)
18 0
|
8天前
yolo-world 源码解析(六)(1)
yolo-world 源码解析(六)
12 0
|
8天前
yolo-world 源码解析(五)(4)
yolo-world 源码解析(五)
19 0
|
8天前
yolo-world 源码解析(五)(1)
yolo-world 源码解析(五)
31 0
|
8天前
yolo-world 源码解析(二)(2)
yolo-world 源码解析(二)
21 0
|
21天前
|
监控 JavaScript 前端开发
《理解 WebSocket:Java Web 开发的实时通信技术》
【4月更文挑战第4天】WebSocket是Java Web实时通信的关键技术,提供双向持久连接,实现低延迟、高效率的实时交互。适用于聊天应用、在线游戏、数据监控和即时通知。开发涉及服务器端实现、客户端连接及数据协议定义,注意安全、错误处理、性能和兼容性。随着实时应用需求增加,WebSocket在Java Web开发中的地位将更加重要。
|
1月前
|
Web App开发 前端开发 开发工具
介绍Web开发的基础知识
介绍Web开发的基础知识
29 7
|
6天前
|
JSON Java fastjson
Spring Boot 底层级探索系列 04 - Web 开发(2)
Spring Boot 底层级探索系列 04 - Web 开发(2)
15 0
|
6天前
|
安全 编译器 PHP
PHP 8.1版本发布:引领Web开发新潮流
PHP编程语言一直是Web开发的主力军,而最新发布的PHP 8.1版本则为开发者们带来了更多创新和便利。本文将介绍PHP 8.1版本的主要特性,包括更快的性能、新的语言功能和增强的安全性,以及如何利用这些功能来提升Web应用程序的质量和效率。

推荐镜像

更多