博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
spring源码解析上下文初始化ContextLoaderListener
阅读量:6161 次
发布时间:2019-06-21

本文共 8213 字,大约阅读时间需要 27 分钟。

hot3.png

 

前言

本文转自“天河聊技术”微信公众号

从本篇文章开始主要介绍spring源码解析相关的spring上下文初始化、bean定义解析、beanFactory创建、初始化、bean定义注册到beanFactory、bean实例化、依赖注入流程中相关的步骤,由于spring源码体系比较庞大,本次主要是跟着程序加载顺序整理,遇到相关关键知识点会单独出来一篇文章,之道这个整个链路顺序解析完毕,后面spring源码合集整理的时候会按照模块进行归类梳理。

 

 

正文

本次主要从ContextLoaderListener这个入口进行跟踪源码,进行spring的源码解析。

 

先简单看下主要的类图

1 bean定义解析相关

06112641_IyfB.jpg

06112641_hPhy.jpg

06112641_WnRr.jpg

2 spring上下文相关

06112641_ndFU.jpg

3 beanProcessor相关

06112641_QwAs.jpg

beanProcessors对bean的过程管理抽象。

 

3spring容器加载

跟踪这个方法

org.springframework.web.context.ContextLoaderListener#contextInitialized

servlet监听器初始时会加载初始化web应用程序上下文这个方法

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

 

跟踪这个方法

org.springframework.web.context.ContextLoader#initWebApplicationContext

public WebApplicationContext initWebApplicationContext(ServletContext servletContext) {//    web上下文是放在servlet上下文中的      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.//       初始化web程序上下文         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);               }//             配置装载和刷新web上下文               configureAndRefreshWebApplicationContext(cwac, servletContext);            }         }         servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context);         ClassLoader ccl = Thread.currentThread().getContextClassLoader();         if (ccl == ContextLoader.class.getClassLoader()) {            currentContext = this.context;         }         else if (ccl != null) {            currentContextPerThread.put(ccl, this.context);         }         if (logger.isDebugEnabled()) {            logger.debug("Published root WebApplicationContext as ServletContext attribute with name [" +                  WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE + "]");         }         if (logger.isInfoEnabled()) {            long elapsedTime = System.currentTimeMillis() - startTime;            logger.info("Root WebApplicationContext: initialization completed in " + elapsedTime + " ms");         }         return this.context;      }      catch (RuntimeException ex) {         logger.error("Context initialization failed", ex);         servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, ex);         throw ex;      }      catch (Error err) {         logger.error("Context initialization failed", err);         servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, err);         throw err;      }   }

从这里可以看出web上下文是存储在servlet上下文中的,key值是

webApplicationContext.ROOT。

 

开始初始化web程序上下文

if (this.context == null) {   this.context = createWebApplicationContext(servletContext);}

 

跟踪这个方法

org.springframework.web.context.ContextLoader#createWebApplicationContext

 

创建web应用上下文

protected WebApplicationContext createWebApplicationContext(ServletContext sc) {      Class
contextClass = determineContextClass(sc);//    如果上下文的类型和ConfigurableWebApplicationContext类型不一致      if (!ConfigurableWebApplicationContext.class.isAssignableFrom(contextClass)) { throw new ApplicationContextException("Custom context class [" + contextClass.getName() + "] is not of type [" + ConfigurableWebApplicationContext.class.getName() + "]");      }//    返回配置上下文对象      return (ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass);   }

 

返回到这个方法

org.springframework.web.context.ContextLoader#initWebApplicationContext

if (cwac.getParent() == null) {

判断上下文是否是活动的,上下文刷新过一次,还没有关闭。

 

进入到这个方法,配置装载和刷新web上下文

org.springframework.web.context.ContextLoader#configureAndRefreshWebApplicationContext

//  配置和刷新web上下文   protected void configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac, ServletContext sc) {      if (ObjectUtils.identityToString(wac).equals(wac.getId())) {         // The application context id is still set to its original default value         // -> assign a more useful id based on available information//       从配置中获取上下文的id         String idParam = sc.getInitParameter(CONTEXT_ID_PARAM);         if (idParam != null) {            wac.setId(idParam);         }         else {            // Generate default id... 生成上下文id字符串 webApplicationContext:+servlet.getContextPath()            wac.setId(ConfigurableWebApplicationContext.APPLICATION_CONTEXT_ID_PREFIX +                  ObjectUtils.getDisplayString(sc.getContextPath()));         }      }      wac.setServletContext(sc);//    获取配置文件路径 contextConfigLocation,配置文件可以是多个的,用,换行分开,可以用占位符      String configLocationParam = sc.getInitParameter(CONFIG_LOCATION_PARAM);      if (configLocationParam != null) {         wac.setConfigLocation(configLocationParam);      }      // The wac environment's #initPropertySources will be called in any case when the context      // is refreshed; do it eagerly here to ensure servlet property sources are in place for      // use in any post-processing or initialization that occurs below prior to #refresh      ConfigurableEnvironment env = wac.getEnvironment();      if (env instanceof ConfigurableWebEnvironment) {         ((ConfigurableWebEnvironment) env).initPropertySources(sc, null);      }//    加载子类实现的上下文      customizeContext(sc, wac);//    上下文刷新      wac.refresh();   }

获取配置文件路径 contextConfigLocation,配置文件可以是多个的,用,换行分开,可以用占位符

String configLocationParam = sc.getInitParameter(CONFIG_LOCATION_PARAM);
//     加载子类实现的上下文      customizeContext(sc, wac);

org.springframework.web.context.ContextLoader#customizeContext 上下文初始化器找到具体要初始化的上下文类进行初始化

protected void customizeContext(ServletContext sc, ConfigurableWebApplicationContext wac) {   List
>> initializerClasses = determineContextInitializerClasses(sc);   for (Class
> initializerClass : initializerClasses) { Class
initializerContextClass = GenericTypeResolver.resolveTypeArgument(initializerClass, ApplicationContextInitializer.class);      if (initializerContextClass != null && !initializerContextClass.isInstance(wac)) { throw new ApplicationContextException(String.format( "Could not apply context initializer [%s] since its generic parameter [%s] " + "is not assignable from the type of application context used by this " + "context loader: [%s]", initializerClass.getName(), initializerContextClass.getName(),               wac.getClass().getName()));      } this.contextInitializers.add(BeanUtils.instantiateClass(initializerClass));   } AnnotationAwareOrderComparator.sort(this.contextInitializers);   for (ApplicationContextInitializer
initializer : this.contextInitializers) { initializer.initialize(wac);   }}

最后

本次介绍到这里,以上内容仅供参考。

转载于:https://my.oschina.net/u/3775437/blog/1810413

你可能感兴趣的文章
js调用.net后台事件,和后台调用前台等方法总结
查看>>
zookeeper的 目录加密
查看>>
Nested Loop,Sort Merge Join,Hash Join
查看>>
Webstrom快捷键
查看>>
BZOJ 2721: [Violet 5]樱花
查看>>
生成某一文件夹内文件清单(批量处理)
查看>>
【转】 SLIC超像素分割详解(一):简介
查看>>
PostgreSQL 数组类型
查看>>
编写一个函数,输入n为偶数时,调用方法求1/2+1/4+...+1/n,当输入n为奇数时,调用函数1/1+1/3+...+1/n...
查看>>
拉马车
查看>>
14.查看信息深入讲解
查看>>
AngularJS(6)-选择框Select
查看>>
初识shell脚本
查看>>
uva 11401思维+预处理
查看>>
9. Palindrome Number
查看>>
android-远程图片获取和本地缓存
查看>>
PHP Smarty变量调节器
查看>>
shell中的字符串操作
查看>>
Node.js 函数
查看>>
Oracle CheckPoint进程
查看>>