美文网首页
二、spring加载之refresh过程(1)配置文件解析

二、spring加载之refresh过程(1)配置文件解析

作者: 悟空嘿 | 来源:发表于2019-03-23 16:33 被阅读0次

日期:2019-03-22

(一)refresh主流程

/**
 * @see AbstractApplicationContext#refresh() 
 */
@Override
public void refresh() throws BeansException, IllegalStateException {
   synchronized (this.startupShutdownMonitor) {
      // Prepare this context for refreshing.
      //准备此上下文以进行刷新
      prepareRefresh();

      // Tell the subclass to refresh the internal bean factory.
      //这里是在子类中启动refreshBeanFactort()的地方
      ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

      // Prepare the bean factory for use in this context.
      // 准备bean工厂以在此上下文中使用。
      prepareBeanFactory(beanFactory);

      try {
         // Allows post-processing of the bean factory in context subclasses.
         // 允许在上下文子类中对bean工厂进行后处理。
         postProcessBeanFactory(beanFactory);

         // Invoke factory processors registered as beans in the context.
         //调用beanFactory的后处理器,这些后处理器是在bean定义中向容器注册的
         invokeBeanFactoryPostProcessors(beanFactory);

         // Register bean processors that intercept bean creation.
         // 注册bean的后处理器,在bean创建过程中调用
         registerBeanPostProcessors(beanFactory);

         // Initialize message source for this context.
         //对上下文中的消息源进行初始化
         initMessageSource();

         // Initialize event multicaster for this context.
         //初始化上下文中的事件机制
         initApplicationEventMulticaster();

         // Initialize other special beans in specific context subclasses.
         //初始化其他的特殊bean
         onRefresh();

         // Check for listener beans and register them.
         //检查监听bean并且将这些bean向容器注册
         registerListeners();

         // Instantiate all remaining (non-lazy-init) singletons.
         //实例化所有的(non-lazy-init)单利
         finishBeanFactoryInitialization(beanFactory);

         // Last step: publish corresponding event.
               //发布容器事件,结束refresh过程
         finishRefresh();
      }catch (BeansException ex) {
         if (logger.isWarnEnabled()) {
            logger.warn("Exception encountered during context initialization - " +
                  "cancelling refresh attempt: " + ex);
         }

         // Destroy already created singletons to avoid dangling resources.
         destroyBeans();

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

         // Propagate exception to caller.
         throw ex;
      }

      finally {
         // Reset common introspection caches in Spring's core, since we
         // might not ever need metadata for singleton beans anymore...
               /**
                * 重置Spring核心中的常见内省缓存,
                * 从此我们开始可能再也不需要单例bean的元数据
                */
         resetCommonCaches();
      }
   }
}

(二)refresh分步解析

1)prepareRefresh()

准备此上下文以进行刷新,设置其启动日期和活动标志以及执行属性源的任何初始化。
/**
 * Prepare this context for refreshing, setting its startup date and
 * active flag as well as performing any initialization of property sources.
 * 准备此上下文以进行刷新,设置其启动日期和活动标志以及执行属性源的任何初始化。
 */
protected void prepareRefresh() {
    //启动时间
   this.startupDate = System.currentTimeMillis();
    //关闭与激活状态
   this.closed.set(false);
   this.active.set(true);

   if (logger.isInfoEnabled()) {
      logger.info("Refreshing " + this);
   }

   // Initialize any placeholder property sources in the context environment
   // 在上下文环境中初始化任何占位符属性源
   //用户可以自定义,继承 对应的ApplicationContext,重写initPropertySources()方法
   initPropertySources();

   // Validate that all properties marked as required are resolvable
   // see ConfigurablePropertyResolver#setRequiredProperties
   // 验证标记为必需的所有属性是否可解析
   //如果设置的property为空,则会报错
   getEnvironment().validateRequiredProperties();

   // Allow for the collection of early ApplicationEvents,
   // to be published once the multicaster is available...
   // 允许收集早期的ApplicationEvents,
   // 一旦多功能车可用就会发布......
   this.earlyApplicationEvents = new LinkedHashSet<ApplicationEvent>();
}

initPropertySources()

初始化配置文件,默认不做任何操作。有些AbstractApplicationContext的子类,做了一些初始化的操作。比如:AbstractRefreshableWebApplicationContext#initPropertySources()

protected void initPropertySources() {
   // For subclasses: do nothing by default.
   // 对于子类:默认情况下不执行任何操作。
}


// AbstractRefreshableWebApplicationContext#initPropertySources()
    protected void initPropertySources() {
        ConfigurableEnvironment env = getEnvironment();
        if (env instanceof ConfigurableWebEnvironment) {
            ((ConfigurableWebEnvironment) env).initPropertySources(this.servletContext, this.servletConfig);
        }
    }
//((ConfigurableWebEnvironment) env).initPropertySources会调用到WebApplicationContextUtils#initServletPropertySources,主要是替换了property中的servletContextInitParams参数和servletConfigInitParams参数。
public static void initServletPropertySources(
      MutablePropertySources propertySources, ServletContext servletContext, ServletConfig servletConfig) {

   Assert.notNull(propertySources, "'propertySources' must not be null");
   if (servletContext != null && propertySources.contains(StandardServletEnvironment.SERVLET_CONTEXT_PROPERTY_SOURCE_NAME) &&
         propertySources.get(StandardServletEnvironment.SERVLET_CONTEXT_PROPERTY_SOURCE_NAME) instanceof StubPropertySource) {
      propertySources.replace(StandardServletEnvironment.SERVLET_CONTEXT_PROPERTY_SOURCE_NAME,
            new ServletContextPropertySource(StandardServletEnvironment.SERVLET_CONTEXT_PROPERTY_SOURCE_NAME, servletContext));
   }
   if (servletConfig != null && propertySources.contains(StandardServletEnvironment.SERVLET_CONFIG_PROPERTY_SOURCE_NAME) &&
         propertySources.get(StandardServletEnvironment.SERVLET_CONFIG_PROPERTY_SOURCE_NAME) instanceof StubPropertySource) {
      propertySources.replace(StandardServletEnvironment.SERVLET_CONFIG_PROPERTY_SOURCE_NAME,
            new ServletConfigPropertySource(StandardServletEnvironment.SERVLET_CONFIG_PROPERTY_SOURCE_NAME, servletConfig));
   }
}

getEnvironment().validateRequiredProperties()

​ 验证标记为必需的所有属性是否可解析,如果设置的property为空,则会报错;最后调用到org.springframework.core.env.AbstractPropertyResolver#validateRequiredProperties();

主要是一个非空检验。相当于,StringUtils.isEmpty()的操作。

@Override
public void validateRequiredProperties() {
   MissingRequiredPropertiesException ex = new MissingRequiredPropertiesException();
   for (String key : this.requiredProperties) {
      if (this.getProperty(key) == null) {
         ex.addMissingRequiredProperty(key);
      }
   }
   if (!ex.getMissingRequiredProperties().isEmpty()) {
      throw ex;
   }
}

2)obtainFreshBeanFactory()

准备此上下文以进行刷新,设置其启动日期和活动标志以及执行属性源的任何初始化。

/**
 * Tell the subclass to refresh the internal bean factory.
 * 告诉子类刷新内部bean工厂。
 * @return the fresh BeanFactory instance
 * @see #refreshBeanFactory()
 * @see #getBeanFactory()
 */
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
  //此实现执行此上下文的基础bean工厂的实际刷新,关闭先前的bean工厂(如果有),并初始化上一个生命周期的下一阶段的新bean工厂。
   refreshBeanFactory();
    //获取刷新后的 beanFactory
   ConfigurableListableBeanFactory beanFactory = getBeanFactory();
   if (logger.isDebugEnabled()) {
      logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);
   }
   return beanFactory;
}

BeanFactory 是spring中最常见的接口之一,很多容器都继承了 这个接口,容易让初学者混淆。但是记住,BeanFactory只是一个规范,这个规范主要规定了获取 bean的口。ApplicationContext也继承了这个接口,不是有时候,并不是为了能够作为一个bean工厂,产生bean,而是方便获取到bean而已。很多继承这个接口的类,并没有具体实现它,而是将实现逻辑交给了org.springframework.beans.factory.support.DefaultListableBeanFactory这样的真正的工厂类。再比如:dubbo中的ReferenceBean,也实现了BeanFatory接口,是为了给调用方提供接口实例。

refreshBeanFactory()

刷新工厂实例。为什么不直接返回,beanfactory实例,而是在使用getBeanFactory()方法去获取。高度封装,让属性的set和get只有一个入口,使得调用方都保持统一,维护和改变都很容易,是值得借鉴的。

/**
 * This implementation performs an actual refresh of this context's underlying
 * bean factory, shutting down the previous bean factory (if any) and
 * initializing a fresh bean factory for the next phase of the context's lifecycle.
    * 此实现执行此上下文的基础bean工厂的实际刷新,关闭先前的bean工厂(如果有),并初始化上一个生命周期的下一阶段的新bean工厂。
 */
@Override
protected final void refreshBeanFactory() throws BeansException {
   // 这里判断是否已经建立了beanFactory,如果存在就销毁并关闭
   if (hasBeanFactory()) {
      destroyBeans();
      closeBeanFactory();
   }
   try {
      // 默认使用DefaultListableBeanFactory
      DefaultListableBeanFactory beanFactory = createBeanFactory();
      //设置ID标识
      beanFactory.setSerializationId(getId());
      //定制bean factory,设置创建beanFactory的许可条件,准入门槛
      customizeBeanFactory(beanFactory);
      //org.springframework.context.support.AbstractXmlApplicationContext
      loadBeanDefinitions(beanFactory);
      synchronized (this.beanFactoryMonitor) {
         this.beanFactory = beanFactory;
      }
   }
   catch (IOException ex) {
      throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
   }
}

//创建beanFactory,使用的是DefaultListableBeanFactory
protected DefaultListableBeanFactory createBeanFactory() {
        /**
         *getInternalParentBeanFactory(),parent对象是在创建ApplicationContext对象时,传入的
         * @see ClassPathXmlApplicationContext#ClassPathXmlApplicationContext(String[], ApplicationContext)
         * 第二个参数,就是parent对象
         */
        return new DefaultListableBeanFactory(getInternalParentBeanFactory());
    }

//定制beanFactory
protected void customizeBeanFactory(DefaultListableBeanFactory beanFactory) {
        //是否允许使用相同名称重新注册不同的定义,默认为true
        if (this.allowBeanDefinitionOverriding != null) {
        beanFactory.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
        }
        // 是否允许循环引用,默认为true
        if (this.allowCircularReferences != null) {
            beanFactory.setAllowCircularReferences(this.allowCircularReferences);
        }
    }

关于循环引用,在单例中是默认是可以进行循环引用的,而在多例中,循环引用是会报错的。

  • loadBeanDefinitions(beanFactory):

    解析xml文件,将解析出来的beanDefinition注册到 DefaultListableBeanFactory.beanDefinitionMap中。

protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
   // Create a new XmlBeanDefinitionReader for the given BeanFactory.
   // beanFactory的xml文件读取包装类
   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));

   // Allow a subclass to provide custom initialization of the reader,
   // then proceed with actually loading the bean definitions.
   initBeanDefinitionReader(beanDefinitionReader);
   //重点方法:调用此方法解析xml,获取beanDefinitionHolder
   loadBeanDefinitions(beanDefinitionReader);
}

相关文章

网友评论

      本文标题:二、spring加载之refresh过程(1)配置文件解析

      本文链接:https://www.haomeiwen.com/subject/gcprvqtx.html