spring启动(3)--AbstractRefreshableApplicationContext

拟墨画扇 提交于 2019-12-30 11:53:12

【推荐】2019 Java 开发者跳槽指南.pdf(吐血整理) >>>

在spring容器中,BeanDefinition是最为重要的元素。那么从我们配置的xml到最终成为被容器管理的bean最起码要经过以下几个过程

第一、资源定位。spring能够定位到我们配置的文件。通常,我们把配置信息放置到xml文件中去,spring要根据自己的规则找到配置文件。

第一、文件解析,将我们配置到xml或者其他文件中的类元素转化成为可以被spring容器认识的元素-beanDefinition

第二、beanDefinition的载入。有了beanDefinition还要将其转化成Spring内幕标示的数据结构。这个结构IOC容器通过HashMap去维护。

FileSystemXmlApplicationContext是bean载入的成熟上下文。他的整个过程包括了bean从配置文件元素,到能够被spring容器管理的所有过程。

FileSystemXmlApplicationContext
public FileSystemXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)
      throws BeansException {
   super(parent);
   setConfigLocations(configLocations);
   if (refresh) {
      refresh();
   }
}
AbstractApplicationContext
public void refresh() throws BeansException, IllegalStateException {
   synchronized (this.startupShutdownMonitor) {
      // Prepare this context for refreshing.
      prepareRefresh();
      // Tell the subclass to refresh the internal bean factory.
      ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
      // Prepare the bean factory for use in this context.
      prepareBeanFactory(beanFactory);
      try {
         // Allows post-processing of the bean factory in context subclasses.
         postProcessBeanFactory(beanFactory);
         // Invoke factory processors registered as beans in the context.
         invokeBeanFactoryPostProcessors(beanFactory);
         // 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();
         // 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;
      }
   }
}



refresh方法里面又包含了12个方法。这12个方法包括了IOC容器启动所有的内容。接下来让我们一个一个看看每个方法都做了什么

1、 // Prepare this context for refreshing.

     prepareRefresh();第一个方法的注释写着为重新启动上下文做准备。也就是说这个方法 主要做了准备工作。准备工作都包括了什么呢?

protected void prepareRefresh() {
 
   // Initialize any placeholder property sources in the context environment//初始化所有在上下文环境中的占位符属性元
   initPropertySources();
   // Validate that all properties marked as required are resolvable
   // see ConfigurablePropertyResolver#setRequiredProperties//验证所有标示为required的属性被正确的设置。
   getEnvironment().validateRequiredProperties();
}

prepareRefresh方法首先将项目的上下文环境都放置进来了。包括war包位置、临时文件位置、占位符、server等等信息。然后通过调用validateRequiredProperties()方法判断requiredProperties里面的属性是否正确的设置进来了。在我的项目中,requiredProperties是空。没有做任何操作。

2、告诉子类刷新内部的bean factory类
// Tell the subclass to refresh the internal bean factory.
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
   refreshBeanFactory();
   ConfigurableListableBeanFactory beanFactory = getBeanFactory();
   if (logger.isDebugEnabled()) {
      logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);
   }
   return beanFactory;
}

该方法首先调用refreshBeanFactory()做了以下几个动作:

1、判断beanFactory是否非空,非空则清空bean容器、清空缓存、清空beanFactory。
2、创建DefaultListableBeanFactory实例。这个过程设置了父子容器的关系。
3、设置上文实例化的DefaultListableBeanFactory的内部属性。包括设置candidate resolver ,该属性决定该bean Definition是否被认为能够autowiring。
4、为指定的bean工厂加载了bean。实际加载bean的是XmlBeanDefinitionReader 实例。接下来初始化reader和加载bean过程由相应的子类实现。

protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
   // 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));
   // Allow a subclass to provide custom initialization of the reader,
   // then proceed with actually loading the bean definitions.//设置reader的属性validating。设置是否使用xml验证,缺省是true initBeanDefinitionReader(beanDefinitionReader);
//加载beanDefinition
   loadBeanDefinitions(beanDefinitionReader);
}protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
   Resource[] configResources = getConfigResources();
   if (configResources != null) {
      reader.loadBeanDefinitions(configResources);
   }
   String[] configLocations = getConfigLocations();
   if (configLocations != null) {
      reader.loadBeanDefinitions(configLocations);
   }
}


我们系统中配置的xml信息最终都已Resouces类的形式被spring读取。


reader.loadBeanDefinitions(configLocations);方法将我们配置的spring xml文件信息解析出来。。
解析进来要包括我们配置的方方面面。包括像autowired属性,各个bean的property属性。这些都是使用reader"笔"来载入的。


protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
//将元素封装成为BeanDefinitionHolder 实例。
 BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
   if (bdHolder != null) {//将autowire、autowire-candidate、class、destroy-method、id,lazy-init、property属性//放置到bdHolder 
      bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
      try {
         // Register the final decorated instance.
         BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
      }
      catch (BeanDefinitionStoreException ex) {
         getReaderContext().error("Failed to register bean definition with name '" +
               bdHolder.getBeanName() + "'", ele, ex);
      }
      // Send registration event.
      getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
   }
}

最终,将beanDefinitions放置到了beanDefinitionMap中。

3、工厂类有了,接下来就是如何让这个工厂类配置信息,让他有容器工厂的样子。配置工厂的标准上下文特性,比如上下文的类加载器和后置处理器等等。 prepareBeanFactory(beanFactory);

除了设置一些关于容器的类信息之外。最重要的就注册进来新的类到容器中。这三个类包含了jdk、servlet容器的信息都在这一步设置进了容器中。

4、 这个过程主要包括后置处理器设置、作用域设置。包括web.xml里面设置的xml文件位置解析postProcessBeanFactory(beanFactory);

protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
//设置后置处理器
   beanFactory.addBeanPostProcessor(new ServletContextAwareProcessor(this.servletContext, this.servletConfig));
   beanFactory.ignoreDependencyInterface(ServletContextAware.class);
   beanFactory.ignoreDependencyInterface(ServletConfigAware.class);
//注册作用域设置。
   WebApplicationContextUtils.registerWebApplicationScopes(beanFactory, this.servletContext);
   WebApplicationContextUtils.registerEnvironmentBeans(beanFactory, this.servletContext, this.servletConfig);
}

     .

五、触发后置处理器。

步骤4已经将后置处理器注册到了工厂类中,接下来就是出发这些工厂类的时候了。


1、从工厂类中获取到后置处理器 

2、后置处理器有优先级。我们要对处理器的前后顺序排序

3、如果没有在工厂类中获取后置处理器,那从工厂加载的bean中寻找后置处理器。触发这些后置处理器。
invokeBeanFactoryPostProcessors(beanFactory);

      
六、注册拦截bean创建的 bean处理器   registerBeanPostProcessors(beanFactory);
1、获取到后置处理器(包括三个类型)
2、将后置处理器增加到了factory中(包括一个监听器后置处理器ApplicationListenerDetector)    

七、   初始化上下文的消息资源  

  initMessageSource();
在factory中注册了一个名称为MESSAGE_SOURCE_BEAN_NAME的类。
如果配置了,则从容器中获取到bean。

如果没有配置,则采用默认的方式创建,将其将其添加到singletonObjects中。  

 

八、初始化上下文的事件广播。         initApplicationEventMulticaster();
   在factory中注册一个名为APPLICATION_EVENT_MULTICASTER_BEAN_NAME的类。如果factory中已经有名称为APPLICATION_EVENT_MULTICASTER_BEAN_NAME的类,则从容器中获取到bean。
如果没有配置,则采用默认的方式创建,将其添加到  singletonObjects中。
// Initialize other special beans in specific context subclasses.

九、初始化铁定上下文子类中其他特殊的bean。

子类中都通过它增加了主题功能的支持。      onRefresh();

protected void onRefresh() {
  this.themeSource = UiApplicationContextUtils.initThemeSource(this);
} // Check for listener beans and register them.
十、查找监听bean,并注册他们。        registerListeners();

//获取到上下文中的监听,将其添加到SimpleApplicationEventMulticaster类的监听器列表中
for (ApplicationListener<?> listener : getApplicationListeners()) {
      getApplicationEventMulticaster().addApplicationListener(listener);
   }
//获取到注册进来的bean中类型为ApplicationListener的监听器,将其添加到SimpleApplicationEventMulticaster类的监听器列表中。   String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);
   for (String lisName : listenerBeanNames) {
      getApplicationEventMulticaster().addApplicationListenerBean(lisName);
   }
}

     
十一、实例化所有剩余类型为单利的bean    finishBeanFactoryInitialization(beanFactory);
包括以下几个步骤:
1、判断类型为CONVERSION_SERVICE_BEAN_NAME类是否存在,存在则将其设置进工厂类中。
2、判断类型为LoadTimeWeaverAware的类是否存在,依赖注入之。
3、取消掉临时类加载器。
4、设置缓存frozenBeanDefinitionNames

5、初始化剩余的非懒加载的单例类。

十二、发布事件。  

finishRefresh();

1、初始化一个类:org.springframework.context.support.DefaultLifecycleProcessor

首先判断factory中是否包含名称为lifecycleProcessor的类,如果有则将其赋值给上下文的lifecycleProcessor中。如果没有则将实例化一个默认值DefaultLifecycleProcessor defaultProcessor = new DefaultLifecycleProcessor();并将其复制给上下文的lifecycleProcessor中

2

2.1、获取容器中加载进来的类中哪个类是Lifecycle.class类型的。

2.2、将Lifecycle.class类型的类放置到容器中返回。

2.3、启动监听容器。

3、

3.1、获取线程池线程

3.2、调用监听方法listener.onApplicationEvent(event),执行监听事件。上文中说@Scheduled方法的时间就是在这个时候出发执行的。

4、没用过,不懂。官方的注解是在LiveBeansView MBean环境中使用。


易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!