文档章节

Spring容器启动流程

halbert918
 halbert918
发布于 2015/11/20 18:14
字数 1043
阅读 163
收藏 0

        ContextLoaderListener:启动时,应用户服务器调用Listener.contextInitialized(ServletContextEvent event)进行初始化整个容器。其初始化大致流程如图:

    启动源码:

/**
 * 初始化context入口
 * Initialize the root web application context.
 */
@Override
public void contextInitialized(ServletContextEvent event) {
   initWebApplicationContext(event.getServletContext());
}

        ContextLoader:真正实现ApplicationContext。

public WebApplicationContext initWebApplicationContext(ServletContext servletContext) {
  if (servletContext.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE) != null) {
     
//......
 
}

  ......  

 
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;
        //判断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
           //通过web.xml配置的参数locatorFactorySelector等初始化初始化父容器环境,
           
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);
           
}
           
//Context容器[加载resource资源文件、创建bean等]
           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;
 
}
}
/**
 * 1、配置web.xml中的参数
 * 2、初始化
 * 实例化beanFactory、读取resource资源、创建BeanDefinition、加载相关组件
 */
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
      String idParam = sc.getInitParameter(CONTEXT_ID_PARAM);
      if (idParam != null) {
         wac.setId(idParam);
      }
      else {
         // Generate default id...
         wac.setId(ConfigurableWebApplicationContext.APPLICATION_CONTEXT_ID_PREFIX +
               ObjectUtils.getDisplayString(sc.getContextPath()));
      }
   }

   wac.setServletContext(sc);
   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);
   }

   //初始化web.xml中配置的自定义contextInitializerClasses等
   customizeContext(sc, wac);
   //加载spring中的配置文件xml、properties等,并创建beanFactory、实例化bean等
   wac.refresh();
}


        AbstractApplicationContext:容器refresh()创建beanFactory、读取resource资源文件、创建bean;

@Override
public void refresh() throws BeansException, IllegalStateException {
   synchronized (this.startupShutdownMonitor) {
      // Prepare this context for refreshing.
      prepareRefresh();

      //1、创建beanFactory(读取resource、加载BeanDefinition并将其注册到beanFactory中)
      // Tell the subclass to refresh the internal bean factory.
      ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
      
      // Prepare the bean factory for use in this context.
      prepareBeanFactory(beanFactory);

      try {
         //beanFactory中添加
         // Allows post-processing of the bean factory in context subclasses.
         postProcessBeanFactory(beanFactory);

         // Invoke factory processors registered as beans in the context.
         invokeBeanFactoryPostProcessors(beanFactory);

         //注册BeanPostProcessor,在实例化bean前后调用,可用于修改bean中信息等
         // Register bean processors that intercept bean creation.
         registerBeanPostProcessors(beanFactory);

         // Initialize message source for this context.
         initMessageSource();

         // Initialize event multicaster for this context.
         initApplicationEventMulticaster();

         // Initialize other special beans in specific context subclasses.
         onRefresh();

         // Check for listener beans and register them.
         registerListeners();
    
         //2、bean实例化
         // Instantiate all remaining (non-lazy-init) singletons.
         finishBeanFactoryInitialization(beanFactory);
      
         // Last step: publish corresponding event.
         finishRefresh();
      }

      catch (BeansException ex) {
         // Destroy already created singletons to avoid dangling resources.
         destroyBeans();

         // Reset 'active' flag.
         cancelRefresh(ex);

         // Propagate exception to caller.
         throw ex;
      }
   }
}

  BeanPostProcessor:自定义BeanPostProcessor的实现可以用户处理bean生成前后相关的逻辑,如修改bean信息,监控bean生成等,可分别调用postProcessBeforeInitialization()、postProcessAfterInitialization()两个方法处理前置和后置逻辑。


 1、通过obtainFreshBeanFactory()创建ConfigurableListableBeanFactory,并通过XmlBeanDefinitionReader读取Resource资源文件,解析为BeanDefinition。

/**
 * 创建beanFactory并加载resource资源文件
 * 解析资源文件、装载BeanDefinition
 * Tell the subclass to refresh the internal bean factory.
 * @return the fresh BeanFactory instance
 * @see #refreshBeanFactory()
 * @see #getBeanFactory()
 */
protected ConfigurableListableBeanFactory() {
   //创建beanFactory并加载resource资源文件
   refreshBeanFactory();
   ConfigurableListableBeanFactory beanFactory = getBeanFactory();
   if (logger.isDebugEnabled()) {
      logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);
   }
   return beanFactory;
}

AbstractRefreshableApplicationContext:

@Override
protected final void refreshBeanFactory() throws BeansException {
   if (hasBeanFactory()) {
      destroyBeans();
      closeBeanFactory();
   }
   try {
      //创建beanFactory---DefaultListableBeanFactory
      DefaultListableBeanFactory beanFactory = createBeanFactory();
      beanFactory.setSerializationId(getId());
      customizeBeanFactory(beanFactory);
      //读取resource、加载BeanDefinition
      loadBeanDefinitions(beanFactory);
      synchronized (this.beanFactoryMonitor) {
         this.beanFactory = beanFactory;
      }
   }
   catch (IOException ex) {
      throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
   }
}

        AbstractXmlApplicationContext:loadBeanDefinitions()通过XmlBeanDefinitionReader读取Resource资源文件,解析为BeanDefinition。

/**
 * Loads the bean definitions via an XmlBeanDefinitionReader.
 * @see org.springframework.beans.factory.xml.XmlBeanDefinitionReader
 * @see #initBeanDefinitionReader
 * @see #loadBeanDefinitions
 */
@Override
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, , IOException {
    //创建XmlBeanDefinitionReader 
   // Create a new XmlBeanDefinitionReader for the given BeanFactory.
   XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);

   // Configure the bean definition reader with this context's
   // resource loading environment.
   beanDefinitionReader.setEnvironment(this.getEnvironment());
   beanDefinitionReader.setResourceLoader(this);
   beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));

   //读取resource、加载BeanDefinition并将其注册到beanFactory的map中
   // Allow a subclass to provide custom initialization of the reader,
   // then proceed with actually loading the bean definitions.
   initBeanDefinitionReader(beanDefinitionReader);
   loadBeanDefinitions(beanDefinitionReader);
}


        2、实例化bean对象:通过finishBeanFactoryInitialization方法实现

© 著作权归作者所有

halbert918
粉丝 2
博文 18
码字总数 14700
作品 0
九龙坡
程序员
私信 提问
Spring基础系列-容器启动流程(1)

原创作品,可以转载,但是请标注出处地址:https://www.cnblogs.com/V1haoge/p/9502069.html 一、概述   我说的容器启动流程涉及两种情况,SSM开发模式和Springboot开发模式。   SSM开发...

唯一浩哥
2018/08/19
0
0
聊聊 SpringCloud 中的父子容器

点击上方“方志朋”,选择“置顶或者星标” 你的关注意义重大! 概述 在引入 SpringCloud 的项目中会多次创建 Spring 容器,本篇从源码角度深入分析具体哪些点会创建 Spring 容器,以及这些容...

方志朋
02/24
0
0
SpringBoot入坑指南之五:应用启动流程分析

概述 Spring Boot框架带来一个Web应用启动的重大变化。Java的Web应用部署都是通过容器,如:Tomcat、JBoss、Weblogic、Undertow等,一般都是将Java的Web应用构建成war、ear包再部署到相关的容...

centychen
02/15
113
2
深入理解 Spring Boot(一)

在过去两三年的 Spring 生态圈,最让人兴奋的莫过于 Spring Boot 框架。或许从命名上就能看出这个框架的设计初衷:快速的启动 Spring 应用。因而 Spring Boot 应用本质上就是一个基于 Spring...

rechardchensir
2018/09/10
151
0
给你一份超详细Spring Boot知识清单

因而 Spring Boot 应用本质上就是一个基于 Spring 框架的应用,它是 Spring 对“约定优先于配置”理念的最佳实践产物,它能够帮助开发者更快速高效地构建基于 Spring 生态圈的应用。 那 Spri...

51CTO技术栈
2018/10/09
0
0

没有更多内容

加载失败,请刷新页面

加载更多

CQRS与AXON

CQRS 看了蛮多文章,只会CRUD,却不懂CQRS,CQRS是遵循DDD思想而产生的一种模式,Command and Query Responsibility Segregation 命令与查询隔离。查询就直接通过正常的模式service调dao层。...

无极之岚
28分钟前
4
0
OSChina 周三乱弹 —— 欢迎你来做产品经理

Osc乱弹歌单(2019)请戳(这里) 【今日歌曲】 @巴拉迪维 :10多次劲歌金曲获奖,更多叱咤歌坛排名,黎明才应该是四大天王之首,只可惜拍的电影太少。单曲循环一个多月的歌,力荐 《无名份的...

小小编辑
43分钟前
78
5
500行代码,教你用python写个微信飞机大战

这几天在重温微信小游戏的飞机大战,玩着玩着就在思考人生了,这飞机大战怎么就可以做的那么好,操作简单,简单上手。 帮助蹲厕族、YP族、饭圈女孩在无聊之余可以有一样东西让他们振作起来!...

上海小胖
今天
8
0
关于AsyncTask的onPostExcute方法是否会在Activity重建过程中调用的问题

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。 本文链接:https://blog.csdn.net/XG1057415595/article/details/86774575 假设下面一种情况...

shzwork
今天
7
0
object 类中有哪些方法?

getClass(): 获取运行时类的对象 equals():判断其他对象是否与此对象相等 hashcode():返回该对象的哈希码值 toString():返回该对象的字符串表示 clone(): 创建并返此对象的一个副本 wait...

happywe
今天
6
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部