写点什么

spring4.1.8 初始化源码学习三部曲之三:AbstractApplicationContext.refresh 方法

作者:程序员欣宸
  • 2022 年 6 月 09 日
  • 本文字数:16935 字

    阅读完需:约 56 分钟

spring4.1.8初始化源码学习三部曲之三:AbstractApplicationContext.refresh方法

欢迎访问我的 GitHub

这里分类和汇总了欣宸的全部原创(含配套源码):https://github.com/zq2599/blog_demos


  • 我们先回顾 ClassPathXmlApplicationContext 类的初始化过程如下代码:


public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)      throws BeansException {  super(parent);  setConfigLocations(configLocations);  if (refresh) {    refresh();  }}
复制代码


  • 三部曲的前两篇学习了 super(parent)setConfigLocations(configLocations)


  1. 《spring4.1.8初始化源码学习三部曲之一:AbstractApplicationContext构造方法》;

  2. 《spring4.1.8初始化源码学习三部曲之二:setConfigLocations方法》;

refresh 方法简介

  • 本章来学习 refresh 方法,具体的源码在 AbstractApplicationContext 类中,该方法的简介请看下面源码中的注释:


@Overridepublic void refresh() throws BeansException, IllegalStateException {  //startupShutdownMonitor对象在spring环境刷新和销毁的时候都会用到,确保刷新和销毁不会同时执行  synchronized (this.startupShutdownMonitor) {    // 准备工作,例如记录事件,设置标志,检查环境变量等,并有留给子类扩展的位置,用来将属性加入到applicationContext中    prepareRefresh();
// 创建beanFactory,这个对象作为applicationContext的成员变量,可以被applicationContext拿来用, // 并且解析资源(例如xml文件),取得bean的定义,放在beanFactory中 ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// 对beanFactory做一些设置,例如类加载器、spel解析器、指定bean的某些类型的成员变量对应某些对象等 prepareBeanFactory(beanFactory);
try { // 子类扩展用,可以设置bean的后置处理器(bean在实例化之后这些后置处理器会执行) postProcessBeanFactory(beanFactory);
// 执行beanFactory后置处理器(有别于bean后置处理器处理bean实例,beanFactory后置处理器处理bean定义) invokeBeanFactoryPostProcessors(beanFactory);
// 将所有的bean的后置处理器排好序,但不会马上用,bean实例化之后会用到 registerBeanPostProcessors(beanFactory);
// 初始化国际化服务 initMessageSource();
// 创建事件广播器 initApplicationEventMulticaster();
// 空方法,留给子类自己实现的,在实例化bean之前做一些ApplicationContext相关的操作 onRefresh();
// 注册一部分特殊的事件监听器,剩下的只是准备好名字,留待bean实例化完成后再注册 registerListeners();
// 单例模式的bean的实例化、成员变量注入、初始化等工作都在此完成 finishBeanFactoryInitialization(beanFactory);
// applicationContext刷新完成后的处理,例如生命周期监听器的回调,广播通知等 finishRefresh(); }
catch (BeansException ex) { logger.warn("Exception encountered during context initialization - cancelling refresh attempt", ex);
// 刷新失败后的处理,主要是将一些保存环境信息的集合做清理 destroyBeans();
// applicationContext是否已经激活的标志,设置为false cancelRefresh(ex);
// Propagate exception to caller. throw ex; } }}
复制代码


  • 接下来逐个分析吧:

prepareRefresh 方法

  • prepareRefresh 方法的源码如下:


protected void prepareRefresh() {  //记录初始化开始时间  this.startupDate = System.currentTimeMillis();  //context是否关闭的标志,设置为false  this.closed.set(false);  //context是否激活的标志,设置为true  this.active.set(true);
if (logger.isInfoEnabled()) { logger.info("Refreshing " + this); }
//留给子类实现的空方法 initPropertySources();
/** AbstractPropertyResolver类的requiredProperties是个集合, 在下面的validateRequiredProperties方法中,都要拿requiredProperties中的元素作为key去检查是否存在对应的环境变量, 如果不存在就抛出异常 */ getEnvironment().validateRequiredProperties();}
复制代码


  • 上述代码中,注意以下两处:


  1. initPropertySources 是个空方法,是留给子类实现的,以 AnnotationConfigWebApplicationContext 类为例,就 overwrite 了 initPropertySources 方法:


@Overrideprotected void initPropertySources() {  ConfigurableEnvironment env = getEnvironment();  if (env instanceof ConfigurableWebEnvironment) {    ((ConfigurableWebEnvironment) env).initPropertySources(this.servletContext, this.servletConfig);  }}
复制代码


  • 跟踪上面的 initPropertySources 方法,最终找到了 WebApplicationContextUtils.initServletPropertySources:


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)); } }
复制代码


  • 上面的代码所做的事情,就是给 context 增加环境变量数据(数据来自 servlet 相关的配置信息),这样 spring 环境就能从 context 中随时 key 取得对应的变量了;


  1. getEnvironment().validateRequiredProperties()的作用是用来校验 context 中是否存在**"某些"**变量,何谓"某些"?来看 validateRequiredProperties 方法,追踪到多层调用,最终在 AbstractPropertyResolver 类的 validateRequiredProperties 方法中实现:


@Overridepublic 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;  }}
复制代码


  • 上述代码显示,如果集合 requiredProperties 中的 name 在 context 中找不到对应的变量,就会抛出异常;

  • 那么问题来了,requiredProperties 集合是何时设置的呢?spring-framework 中并没有调用,但是官方的单元测试源码给我们了启发,如下图:


  • 如上图红框,如果业务需要确保某些变量在 spring 环境中必须存在,就可以调用 setRequiredProperties 方法将变量的 name 传递进去,这样 validateRequiredProperties 方法就会做检查了,我们可以基于现有的各种 ApplicationContext 实现自己定制一个 Context 类,确保在 validateRequiredProperties 方法调用之前调用 setRequiredProperties 方法将变量的 name 传递进去(例如重写 initPropertySources),就能让 spring 帮我们完成检查了;

obtainFreshBeanFactory()

  • 接下来看**ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();**得到临时变量 beanFactory,先看看 ConfigurableListableBeanFactory 和 BeanFactory 的关系:



  • 再看看 obtainFreshBeanFactory 方法:


protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {  //由子类创建beanFactory  refreshBeanFactory();  //取得子类创建好的beanFactory,作为obtainFreshBeanFactory方法的返回值返回  ConfigurableListableBeanFactory beanFactory = getBeanFactory();  if (logger.isDebugEnabled()) {    logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);  }  return beanFactory;}
复制代码


  • 上述代码中有的 refreshBeanFactory 需要细看;

refreshBeanFactory 方法

  • refreshBeanFactory 方法,在 AbstractApplicationContext 类中是抽象方法,具体实现在子类中,以其子类 AbstractRefreshableApplicationContext 为例,我们来看看 refreshBeanFactory 方法的实现:


@Overrideprotected final void refreshBeanFactory() throws BeansException {  //如果beanFactory已经存在,就销毁context管理的所有bean,并关闭beanFactory  if (hasBeanFactory()) {    //其实就是调用一些集合的clear方法,解除对一些实例的引用,参考DefaultSingletonBeanRegistry.destroySingletons方法    destroyBeans();    //关闭当前的beanFactory,其实就是将成员变量beanFactory设置为null    closeBeanFactory();  }  try {    DefaultListableBeanFactory beanFactory = createBeanFactory();    beanFactory.setSerializationId(getId());    customizeBeanFactory(beanFactory);    loadBeanDefinitions(beanFactory);    synchronized (this.beanFactoryMonitor) {      this.beanFactory = beanFactory;    }  }  catch (IOException ex) {    throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);  }}
复制代码


  • createBeanFactory 方法实际上返回的是一个 DefaultListableBeanFactory 实例:


protected DefaultListableBeanFactory createBeanFactory() {  return new DefaultListableBeanFactory(getInternalParentBeanFactory());}
复制代码


  • 接下来的 customizeBeanFactory 方法是留给子类 OverWrite 的,该方法的说明和源码如下,说明中推荐通过 OverWrite 的方式对现有 beanFactory 做特别的设置:


/*** Customize the internal bean factory used by this context.* Called for each {@link #refresh()} attempt.* <p>The default implementation applies this context's* {@linkplain #setAllowBeanDefinitionOverriding "allowBeanDefinitionOverriding"}* and {@linkplain #setAllowCircularReferences "allowCircularReferences"} settings,* if specified. Can be overridden in subclasses to customize any of* {@link DefaultListableBeanFactory}'s settings.* @param beanFactory the newly created bean factory for this context* @see DefaultListableBeanFactory#setAllowBeanDefinitionOverriding* @see DefaultListableBeanFactory#setAllowCircularReferences* @see DefaultListableBeanFactory#setAllowRawInjectionDespiteWrapping* @see DefaultListableBeanFactory#setAllowEagerClassLoading*/protected void customizeBeanFactory(DefaultListableBeanFactory beanFactory) {  if (this.allowBeanDefinitionOverriding != null) {    //allowBeanDefinitionOverriding表示是否允许注册一个同名的类来覆盖原有类(注意是类,不是实例)    beanFactory.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);  }  if (this.allowCircularReferences != null) {    //allowCircularReferences表示是否运行多个类之间的循环引用    beanFactory.setAllowCircularReferences(this.allowCircularReferences);  }}
复制代码


  • loadBeanDefinitions 在 AbstractRefreshableApplicationContext 类中是个抽象方法,留给子类实现,作用是把所有 bean 的定义后保存在 context 中,以 AbstractXmlApplicationContext 为例,看看 loadBeanDefinitions 方法做了什么:


/*** Loads the bean definitions via an XmlBeanDefinitionReader.* @see org.springframework.beans.factory.xml.XmlBeanDefinitionReader* @see #initBeanDefinitionReader* @see #loadBeanDefinitions*/@Overrideprotected 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. initBeanDefinitionReader(beanDefinitionReader); loadBeanDefinitions(beanDefinitionReader);}
复制代码


  • 以上代码可见,加载 bean 的定义是通过 XmlBeanDefinitionReader 来完成的,重点关注 loadBeanDefinitions 方法:


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);  }}
复制代码


  • 上述代码中的 getConfigResources()和 getConfigLocations(),究竟哪个会返回值有效数据呢?这就要去看 ClassPathXmlApplicationContext 的构造方法了:


//这个方法设置的是configLocationspublic ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)      throws BeansException {
super(parent); setConfigLocations(configLocations); if (refresh) { refresh(); }}
//这个方法设置的是这个方法设置的是configResourcespublic ClassPathXmlApplicationContext(String[] paths, Class<?> clazz, ApplicationContext parent) throws BeansException {
super(parent); Assert.notNull(paths, "Path array must not be null"); Assert.notNull(clazz, "Class argument must not be null"); this.configResources = new Resource[paths.length]; for (int i = 0; i < paths.length; i++) { this.configResources[i] = new ClassPathResource(paths[i], clazz); } refresh();}
复制代码


  • 因此,到底是 configLocations 还是 configResources ,和我们使用哪个构造方法来实例化 applicationContext 对象有关;

  • 如果我们实例化 applicationContext 对象的方式是 new ClassPathXmlApplicationContext("applicationContext.xml"),那么 setConfigLocations 方法就会被调用,因此 loadBeanDefinitions 方法内部,实际执行的代码如下:


String[] configLocations = getConfigLocations();  if (configLocations != null) {    reader.loadBeanDefinitions(configLocations);  }
复制代码


  • 现在可以来看 AbstractBeanDefinitionReader 类的 loadBeanDefinitions(String... locations)方法了:


public int loadBeanDefinitions(String... locations) throws BeanDefinitionStoreException {    Assert.notNull(locations, "Location array must not be null");    int counter = 0;    for (String location : locations) {      counter += loadBeanDefinitions(location);    }    return counter;  }
复制代码


  • 展开上面 for 循环中调用的方法:


public int loadBeanDefinitions(String location, Set<Resource> actualResources) throws BeanDefinitionStoreException {    ResourceLoader resourceLoader = getResourceLoader();    if (resourceLoader == null) {      throw new BeanDefinitionStoreException(          "Cannot import bean definitions from location [" + location + "]: no ResourceLoader available");    }
if (resourceLoader instanceof ResourcePatternResolver) { // Resource pattern matching available. try { Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location); int loadCount = loadBeanDefinitions(resources); if (actualResources != null) { for (Resource resource : resources) { actualResources.add(resource); } } if (logger.isDebugEnabled()) { logger.debug("Loaded " + loadCount + " bean definitions from location pattern [" + location + "]"); } return loadCount; } catch (IOException ex) { throw new BeanDefinitionStoreException( "Could not resolve bean definition resource pattern [" + location + "]", ex); } } else { // Can only load single resources by absolute URL. Resource resource = resourceLoader.getResource(location); int loadCount = loadBeanDefinitions(resource); if (actualResources != null) { actualResources.add(resource); } if (logger.isDebugEnabled()) { logger.debug("Loaded " + loadCount + " bean definitions from location [" + location + "]"); } return loadCount; } }
复制代码


  • 以上方法中,首先要记得 resourceLoader 是 ClassPathXmlApplicationContext(beanDefinitionReader.setResourceLoader(this)这行代码),所有 resourceLoader.getResource(location)这行代码最终会调用 PathMatchingResourcePatternResolver 类的 getResources(String locationPattern)方法得到 bean 有关的 Resource 对象;得到 Resource 对象后,接着会调用 loadBeanDefinitions(Resource... resources)方法来加载 bean 的定义了,最终是调用 XmlBeanDefinitionReader.loadBeanDefinitions(EncodedResource encodedResource)方法:


public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {    Assert.notNull(encodedResource, "EncodedResource must not be null");    if (logger.isInfoEnabled()) {      logger.info("Loading XML bean definitions from " + encodedResource.getResource());    }
Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get(); if (currentResources == null) { currentResources = new HashSet<EncodedResource>(4); this.resourcesCurrentlyBeingLoaded.set(currentResources); } if (!currentResources.add(encodedResource)) { throw new BeanDefinitionStoreException( "Detected cyclic loading of " + encodedResource + " - check your import definitions!"); } try { InputStream inputStream = encodedResource.getResource().getInputStream(); try { InputSource inputSource = new InputSource(inputStream); if (encodedResource.getEncoding() != null) { inputSource.setEncoding(encodedResource.getEncoding()); } return doLoadBeanDefinitions(inputSource, encodedResource.getResource()); } finally { inputStream.close(); } } catch (IOException ex) { throw new BeanDefinitionStoreException( "IOException parsing XML document from " + encodedResource.getResource(), ex); } finally { currentResources.remove(encodedResource); if (currentResources.isEmpty()) { this.resourcesCurrentlyBeingLoaded.remove(); } } }
复制代码


  • 上述代码可见,重要的是通过 Resource 对象得到 InputStream,再调用 doLoadBeanDefinitions 方法:


protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)      throws BeanDefinitionStoreException {    try {      Document doc = doLoadDocument(inputSource, resource);      return registerBeanDefinitions(doc, resource);    }    ...
复制代码


  • 上面是加载 bean 定义的关键代码:先制作 Document 对象,再调用 registerBeanDefinitions 方法,最终会将每个 bean 的定义放入 DefaultListableBeanFactory 的 beanDefinitionMap 中,详细的堆栈如下图:


  • 完成了 bean 定义的注册,可以回到 AbstractRefreshableApplicationContext.refreshBeanFactory 方法了,看看 loadBeanDefinitions(beanFactory)之后的代码:


synchronized (this.beanFactoryMonitor) {      this.beanFactory = beanFactory;    }
复制代码


  • 至此,refreshBeanFactory 方法分析完毕,该方法所做的事情:把 xml 文件中的 bean 定义被解析后,存放在 DefaultListableBeanFactory 的 beanDefinitionMap 中;

  • 现在回到主线的 AbstractApplicationContext.refresh()方法内,obtainFreshBeanFactory()我们已经分析完毕,所有 bean 定义都被存放在 beanFactory 这个临时变量对应的实例中;

prepareBeanFactory

  • 接下来是 prepareBeanFactory(beanFactory),看一下此方法的源码:


protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {  //设置类加载器  beanFactory.setBeanClassLoader(getClassLoader());  //设置解析器,用于解析bean的定义中出现的Spel表达式表达式  beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));  //设置一个注册接口,该接口只有一个方法registerCustomEditors,用来设置自定义的转换器  beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));
// 部署一个bean的后置处理器ApplicationContextAwareProcessor,用于将spring的环境信息注入到实例化的bean之中 beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this)); //bean在初始化的时候,如果有属性的类型为ResourceLoaderAware,则该属性不会被依赖注入 beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class); beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class); beanFactory.ignoreDependencyInterface(MessageSourceAware.class); beanFactory.ignoreDependencyInterface(ApplicationContextAware.class); beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
// BeanFactory interface not registered as resolvable type in a plain factory. // MessageSource registered (and found for autowiring) as a bean. //bean如果有个属性的类型为BeanFactory.class,那么该属性会被设置为beanFactory beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory); beanFactory.registerResolvableDependency(ResourceLoader.class, this); beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this); beanFactory.registerResolvableDependency(ApplicationContext.class, this);
// Detect a LoadTimeWeaver and prepare for weaving, if found. if (beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) { // 部署一个bean的后置处理器ApplicationContextAwareProcessor,用于AOP静态代理相关的处理 beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory)); // Set a temporary ClassLoader for type matching. beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader())); }
// Register default environment beans. if (!beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) { //注册一个bean beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment()); } if (!beanFactory.containsLocalBean(SYSTEM_PROPERTIES_BEAN_NAME)) { beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, getEnvironment().getSystemProperties()); } if (!beanFactory.containsLocalBean(SYSTEM_ENVIRONMENT_BEAN_NAME)) { beanFactory.registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME, getEnvironment().getSystemEnvironment()); }}
复制代码


  • 上述代码中有以下几点需要注意:


  1. beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment())),此方法要配合 AbstractBeanFactory.registerCustomEditors 方法一起看更好理解:addPropertyEditorRegistrar 方法向 propertyEditorRegistrars 属性中放入了一个 registrar,之后调用 registerCustomEditors 方法的时候,会用到 propertyEditorRegistrars 中的 registrar,调用这些 registrar 的 registerCustomEditors 方法,完成自定义的转换器的设置;

  2. beanFactory.addBeanPostProcessor 方法用来注入后置处理器,在 bean 实例被创建后,初始化方法被执行的前后,后置处理器的 postProcessBeforeInitialization、postProcessAfterInitialization 这两个方法会分别被调用;

  3. beanFactory.ignoreDependencyInterface 设置了依赖注入时要忽略的接口,例如 bean 有个属性类型是 ResourceLoaderAware,那么该属性不会被注入 ResourceLoaderAware 类型的实例;

  4. beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory)是特殊设置,如果一个 bean 有个属性的类型是 BeanFactory,那么该属性会被设置为 beanFactory 这个实例;


  • 总的来说 prepareBeanFactory 方法就是为 beanFactory 做一些设置工作,传入一些后面会用到的参数和工具类,再在 spring 容器中创建一些 bean;

postProcessBeanFactory

  • postProcessBeanFactory 方法是留给子类扩展的,可以在 bean 实例初始化之前注册后置处理器(类似 prepareBeanFactory 方法中的 beanFactory.addBeanPostProcessor),以子类 AbstractRefreshableWebApplicationContext 为例,其 postProcessBeanFactory 方法如下:


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); }
复制代码


  • 可见除了 WebApplicationContextUtils 类的工作之外,其余的都是和 prepareBeanFactory 方法中类似的处理;

invokeBeanFactoryPostProcessors

  • invokeBeanFactoryPostProcessors 方法用来执行 BeanFactory 实例的后置处理器 BeanFactoryPostProcessor 的 postProcessBeanFactory 方法,这个后置处理器除了原生的,我们也可以自己扩展,用来对 Bean 的定义做一些修改,由于此时 bean 还没有实例化,所以不要在自己扩展的 BeanFactoryPostProcessor 中调用那些会触发 bean 实例化的方法(例如 BeanFactory 的 getBeanNamesForType 方法),源码的文档中有相关说明,如下图红框所示,不要触发 bean 的实例化,如果要处理 bean 实例请在 BeanPostProcessor 中进行:


registerBeanPostProcessors

  • registerBeanPostProcessors 方法的代码略多,就不在此贴出来了,简单的说,就是找出所有的 bean 的后置处理器(注意,是 bean 的后置处理器,不是 beanFactory 的后置处理器,bean 后置处理器处理的是 bean 实例,beanfactory 后置处理器处理的是 bean 的定义),然后将这些 bean 的后置处理器分为三类:


  1. 实现了顺序接口 Ordered.class 的,先放入 orderedPostProcessors 集合,排序后顺序加入 beanFactory 的 bean 后处理集合中;

  2. 既没有实现 Ordered.class,也没有实现 PriorityOrdered.class 的后置处理器,也加入到 beanFactory 的 bean 后处理集合中;

  3. 最后是实现了优先级接口 PriorityOrdered.class 的,排序后顺序加入 beanFactory 的 bean 后处理集合中;


  • registerBeanPostProcessors 方法执行完毕后,beanFactory 中已经保存了有序的 bean 后置处理器,在 bean 实例化之后,会依次使用这些后置处理器对 bean 实例来做对应的处理;

initMessageSource

  • initMessageSource 方法用来准备国际化资源相关的,将实现了 MessageSource 接口的 bean 存放在 ApplicationContext 的成员变量中,先看是否有配置,如果有就实例化,否则就创建一个 DelegatingMessageSource 实例的 bean;

initApplicationEventMulticaster

  • spring 中有事件、事件广播器、事件监听器等组成事件体系,在 initApplicationEventMulticaster 方法中对事件广播器做初始化,如果找不到此 bean 的配置,就创建一个 SimpleApplicationEventMulticaster 实例作为事件广播器的 bean,并且保存- 为 applicationContext 的成员变量 applicationEventMulticaster;

onRefresh

  • onRefresh 是个空方法,留给子类自己实现的,在实例化 bean 之前做一些 ApplicationContext 相关的操作,以子类 AbstractRefreshableWebApplicationContext 为例,看看它的 onRefresh 方法:


@Overrideprotected void onRefresh() {  this.themeSource = UiApplicationContextUtils.initThemeSource(this);}
复制代码


  • 可见是做了主题相关的初始化,并保存在 ApplicationContext 的成员变量中;

registerListeners

  • 方法名为 registerListeners,看名字像是将监听器注册在事件广播器中,但实际情况并非如此,只有一些特殊的监听器被注册了,那些在 bean 配置文件中实现了 ApplicationListener 接口的类还没有实例化,所以此处只是将其 name 保存在广播器中,将这些监听器注册在广播器的操作是在 bean 的后置处理器中完成的,那时候 bean 已经实例化完成了,我们看代码:


protected void registerListeners() {  // 注册的都是特殊的事件监听器,而并非配置中的bean  for (ApplicationListener<?> listener : getApplicationListeners()) {    getApplicationEventMulticaster().addApplicationListener(listener);  }
// Do not initialize FactoryBeans here: We need to leave all regular beans // uninitialized to let post-processors apply to them! // 根据接口类型找出所有监听器的名称 String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false); for (String listenerBeanName : listenerBeanNames) { // 这里只是把监听器的名称保存在广播器中,并没有将这些监听器实例化!!! getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName); }}
复制代码

finishBeanFactoryInitialization

  • finishBeanFactoryInitialization 方法做了两件事:

  • beanFactory 对象的初始化;

  • 我们在 bean 配置文件中配置的那些单例的 bean,都是在 finishBeanFactoryInitialization 方法中实例化的;

  • 看代码:


protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {  // Initialize conversion service for this context.  // 实例化类型转换的bean,并保存在ApplicationContext中  if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME) &&      beanFactory.isTypeMatch(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)) {    beanFactory.setConversionService(    beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class));  }
// Initialize LoadTimeWeaverAware beans early to allow for registering their transformers early. // 实例化LoadTimeWeaverAware接口的bean,用于ApsectJ的类加载期织入的处理 String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false); for (String weaverAwareName : weaverAwareNames) { getBean(weaverAwareName); }
// Stop using the temporary ClassLoader for type matching. // 确保临时的classLoader为空,临时classLoader一般被用来做类型匹配的 beanFactory.setTempClassLoader(null);
// Allow for caching all bean definition metadata, not expecting further changes. // 将一个标志设置为true,表示applicationContext已经缓存了所有bean的定义,这些bean的name都被保存在applicationContext的frozenBeanDefinitionNames成员变量中,相当于一个快照,记录了当前那些bean的定义已经拿到了 beanFactory.freezeConfiguration();
// 实例化所有还未实例化的单例bean beanFactory.preInstantiateSingletons();}
复制代码


  • 上述代码中,beanFactory.preInstantiateSingletons()需要展开仔细看:


public void preInstantiateSingletons() throws BeansException {    if (this.logger.isDebugEnabled()) {      this.logger.debug("Pre-instantiating singletons in " + this);    }
// Iterate over a copy to allow for init methods which in turn register new bean definitions. // While this may not be part of the regular factory bootstrap, it does otherwise work fine. List<String> beanNames = new ArrayList<String>(this.beanDefinitionNames);
// Trigger initialization of all non-lazy singleton beans... for (String beanName : beanNames) { // 获取bean的定义,该定义已经和父类定义做了合并 RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName); // 非抽象类、是单例、非懒加载 if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) { //FactoryBean的处理 if (isFactoryBean(beanName)) { final FactoryBean<?> factory = (FactoryBean<?>) getBean(FACTORY_BEAN_PREFIX + beanName); boolean isEagerInit; if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) { isEagerInit = AccessController.doPrivileged(new PrivilegedAction<Boolean>() { @Override public Boolean run() { return ((SmartFactoryBean<?>) factory).isEagerInit(); } }, getAccessControlContext()); } else { isEagerInit = (factory instanceof SmartFactoryBean && ((SmartFactoryBean<?>) factory).isEagerInit()); } if (isEagerInit) { getBean(beanName); } } else { //非FactoryBean的实例化、初始化 getBean(beanName); } } }
// Trigger post-initialization callback for all applicable beans... // 单例实例化完成后,如果实现了SmartInitializingSingleton接口,afterSingletonsInstantiated就会被调用,此处用到了特权控制逻辑AccessController.doPrivileged for (String beanName : beanNames) { Object singletonInstance = getSingleton(beanName); if (singletonInstance instanceof SmartInitializingSingleton) { final SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance; if (System.getSecurityManager() != null) { AccessController.doPrivileged(new PrivilegedAction<Object>() { @Override public Object run() { smartSingleton.afterSingletonsInstantiated(); return null; } }, getAccessControlContext()); } else { smartSingleton.afterSingletonsInstantiated(); } } }}
复制代码


  • 上述代码中,要重点关注 getBean(beanName),这里面会实例化 bean,由于内容太多不适合在本章细说,这里先将实例化 bean 的调用路径整理出来:


AbstractBeanFactory.getBean(String name)
->
AbstractBeanFactory.doGetBean(String name, Class<T> requiredType, final Object[] args, boolean typeCheckOnly)
->
DefaultSingletonBeanRegistry.getSingleton(String beanName, ObjectFactory<?> singletonFactory)
->
AbstractBeanFactory.doGetBean中的匿名类的getObject方法
->
AbstractAutowireCapableBeanFactory.createBean(String beanName, RootBeanDefinition mbd, Object[] args)
->AbstractAutowireCapableBeanFactory.doCreateBean(final String beanName, final RootBeanDefinition mbd, Object[] args)
->
AbstractAutowireCapableBeanFactory.createBeanInstance(String beanName, RootBeanDefinition mbd, Object[] args)
->
instantiateBean(final String beanName, final RootBeanDefinition mbd)
->
SimpleInstantiationStrategy.instantiate(RootBeanDefinition bd, String beanName, BeanFactory owner)
->
BeanUtils.instantiateClass(Constructor<T> ctor, Object... args)
->
Constructor.newInstance(Object ... initargs)
->
bean的构造方法
复制代码


  • 以上调用路径可以看出,bean 对象的创建是 BeanUtils.instantiateClass 方法通过反射来创建的;

  • 再来看看 bean 的成员变量是什么时候被注入值的,如下图,AbstractAutowireCapableBeanFactory.doCreateBean 方法中,先调用 createBeanInstance 创建 bean 的对象(绿框所示),再调用 populateBean 方法给成员变量注入内容(红框所示):



  • 将注入值的调用堆栈整理如下,可见是也是通过反射完成注入的:


AbstractAutowireCapableBeanFactory.populateBean(String beanName, RootBeanDefinition mbd, BeanWrapper bw)
->
AbstractAutowireCapableBeanFactory.applyPropertyValues(String beanName, BeanDefinition mbd, BeanWrapper bw, PropertyValues pvs)
->
AbstractPropertyAccessor.setPropertyValues(PropertyValues pvs)
->
BeanWrapperImpl.setPropertyValue(PropertyValue pv)
->
Method.invoke(Object obj, Object... args)
复制代码


  • 看过了成员变量注入的逻辑后,还有个重要的逻辑也请关注,就是 bean 的初始化(bean 的配置文件中的 init-method 属性),AbstractAutowireCapableBeanFactory.doCreateBean 方法中,在调用 populateBean 方法给成员变量注入值之后,马上调用 initializeBean 方法进行初始化操作,调用堆栈整理如下:


AbstractAutowireCapableBeanFactory.initializeBean(final String beanName, final Object bean, RootBeanDefinition mbd)
->
AbstractAutowireCapableBeanFactory.invokeInitMethods(String beanName, final Object bean, RootBeanDefinition mbd)
->
AbstractAutowireCapableBeanFactory.invokeCustomInitMethod(String beanName, final Object bean, RootBeanDefinition mbd)
->
Method.invoke(Object obj, Object... args)
复制代码


  • 可见依旧是通过反射来执行初始化方法;

finishRefresh

  • 最后一个方法是 finishRefresh,这是在 bean 的实例化、初始化等完成后的一些操作,例如生命周期变更的回调,发送 applicationContext 刷新完成的广播等,展开看看:


protected void finishRefresh() {  // 检查是否已经配置了生命周期处理器,如果没有就new一个DefaultLifecycleProcessor  initLifecycleProcessor();
// 找到所有实现了Lifecycle接口的bean,按照每个bean设置的生命周期阶段进行分组,再依次调用每个分组中每个bean的start方法,完成生命周期监听的通知 getLifecycleProcessor().onRefresh();
// 创建一条代表applicationContext刷新完成的事件,交给广播器去广播 publishEvent(new ContextRefreshedEvent(this));
// 如果配置了MBeanServer,就完成在MBeanServer上的注册 LiveBeansView.registerApplicationContext(this);}
复制代码


  • 至此,整个初始化流程咱们已经过了一遍了,但是篇幅有限,很多细节都没有展开,另外很多子类也有自己独特的扩展,这些都需要花时间去细看,希望本文能帮您整理思路,从总体上了解初始化的各个关键步骤,以免过早陷入细节;

欢迎关注 InfoQ:程序员欣宸

学习路上,你不孤单,欣宸原创一路相伴...

发布于: 2022 年 06 月 09 日阅读数: 17
用户头像

搜索"程序员欣宸",一起畅游Java宇宙 2018.04.19 加入

前腾讯、前阿里员工,从事Java后台工作,对Docker和Kubernetes充满热爱,所有文章均为作者原创,个人Github:https://github.com/zq2599/blog_demos

评论

发布
暂无评论
spring4.1.8初始化源码学习三部曲之三:AbstractApplicationContext.refresh方法_Java_程序员欣宸_InfoQ写作社区