【挑战 Spring】—– Spring IOC 源码调试二

前言

昨晚做了个梦......,好!上篇Spring IOC 源码调试一的进度进行到ClassPathXmlApplicationContext类构造方法中的refresh()方法,那这一篇就开始进入到大名鼎鼎的refresh()方法。

项目结构

这是调试代码

开始调试

1.执行ClassPathXmlApplicationContextrefresh()方法

其中会先判断if (refresh),这个参数默认是true,点进new ClassPathXmlApplicationContext(location)这个代码中的构造方法就可以看到。然后执行refresh()方法,但是该方法被封装到了父类 AbstractApplicationContext中。

public ClassPathXmlApplicationContext( String[] configLocations, boolean refresh, @Nullable
									ApplicationContext parent)throws BeansException {
	super(parent);
	setConfigLocations(configLocations);
	if (refresh) {
		// 调用父类 AbstractApplicationContext#refresh() 的方法
		refresh();
	}
}
复制代码

2.执行AbstractApplicationContext类的refresh()方法

此时代码进到AbstractApplicationContext类中,下面是refresh()总揽,和一些方法注释。

public void refresh() throws BeansException, IllegalStateException {
		synchronized (this.startupShutdownMonitor) {
			// Prepare this context for refreshing.
			prepareRefresh();
			// 创建并初始化 BeanFactory 容器(DefaultListableBeanFactory对象),后面很多方法都需要这个参数
			ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
			// 填充 BeanFactory 功能
			//  比如 context的 ClassLoader 和 后置处理器等等。
			prepareBeanFactory(beanFactory);
			try {
				// 提供子类覆盖的额外处理,即子类处理自定义的BeanFactoryPostProcess
				postProcessBeanFactory(beanFactory);
				// 激活各种BeanFactory处理器
				invokeBeanFactoryPostProcessors(beanFactory);
				// 注册拦截Bean创建的Bean处理器,即注册 BeanPostProcessor
				registerBeanPostProcessors(beanFactory);
				// 初始化上下文中的资源文件,如国际化文件的处理等
				initMessageSource();
				// 初始化上下文事件广播器
				initApplicationEventMulticaster();
				//预留给 AbstractApplicationContext 的子类用于初始化其他特殊的 bean,该方法需要在所有单例 bean 初始化之前调用。
				onRefresh();
				// Check for listener beans and register them.
				registerListeners();
				// 初始化剩下的单例Bean(非延迟加载的)
				finishBeanFactoryInitialization(beanFactory);
				// Last step: publish corresponding event.
				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...
				resetCommonCaches();
			}
		}
	}
复制代码
2-1.执行AbstractApplicationContext类的prepareRefresh()方法

这个方法意思就是准备好应用上下文环境。

protected void prepareRefresh() {
   // Switch to active.
   // 设置启动日期
   this.startupDate = System.currentTimeMillis();
   // 设置 context 是否关闭的 状态
   this.closed.set(false);
   // 设置当前容器激活状态
   this.active.set(true);
   if (logger.isDebugEnabled()) {
      if (logger.isTraceEnabled()) {
         logger.trace("Refreshing " + this);
      } else {
         logger.debug("Refreshing " + getDisplayName());
      }
   }
   // Initialize any placeholder property sources in the context environment.
   //初始化context environment(上下文环境)中的占位符属性来源(该方法由子类去实现)
   initPropertySources();
   // Validate that all properties marked as required are resolvable:
   // see ConfigurablePropertyResolver#setRequiredProperties
   // 对 容器上下文环境 中的属性进行必要的验证
   getEnvironment().validateRequiredProperties();
   // 实例化一个 LinkedHashSet 存储 预刷新应用的监听器
   if (this.earlyApplicationListeners == null) {
      this.earlyApplicationListeners = new LinkedHashSet<>(this.applicationListeners);
   } else {
      // Reset local application listeners to pre-refresh state.
      this.applicationListeners.clear();
      this.applicationListeners.addAll(this.earlyApplicationListeners);
   }
   // 允许收集早期的ApplicationEvents,一旦多主机可用就要发布
   // todo 什么意思? 作用?
   this.earlyApplicationEvents = new LinkedHashSet<>();
}
复制代码
2-2.执行AbstractApplicationContext类的obtainFreshBeanFactory方法

obtainFreshBeanFactory方法中又调用了refreshBeanFactory()方法,但是在AbstractApplicationContext类中该方法是个空方法,并且此时调用refreshBeanFactory()方法的类依然是ClassPathApplicationContext对象,所以下一步进入到的ClassPathApplicationContext的父类AbstractRefreshableApplicationContextrefreshBeanFactory()方法中(多跟几遍代码,ClassPathApplicationContext类的继承关系就会理清楚了)

protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
   //初始化容器核心方法
   refreshBeanFactory();
   return getBeanFactory();
}
复制代码
2-3. 执行AbstractRefreshableApplicationContextrefreshBeanFactory()方法

该方法中重要操作有:

  1. DefaultListableBeanFactory beanFactory = createBeanFactory()·:创建 BeanFactory 容器对象
  2. loadBeanDefinitions(beanFactory) :加载 BeanDefinition 们,具体提的类实现不同的方法
  3. this.beanFactory = beanFactory :将容器对象赋值给AbstractRefreshableApplicationContextprivate DefaultListableBeanFactory beanFactory属性
/**
 * 该方法是被final修饰 不允许被子类修改
 * 该方法是 实例化容器 的重要方法
 */
@Override
protected final void refreshBeanFactory() throws BeansException {
   // 若已有 BeanFactory ,销毁它的 Bean 们,并销毁 BeanFactory
   if (hasBeanFactory()) {
      destroyBeans();
      closeBeanFactory();
   }
   try {
      //创建 BeanFactory 容器对象
      DefaultListableBeanFactory beanFactory = createBeanFactory();
      // 设置 BeanFactory 的序列id
      beanFactory.setSerializationId(getId());
      // 定制 BeanFactory 设置相关属性
      customizeBeanFactory(beanFactory);
      //  加载 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);
   }
}
复制代码
2-4. (重点)执行AbstractRefreshableApplicationContextcreateBeanFactory()方法创建容器对象
2-4-1.执行DefaultListableBeanFactory(容器对象)的构造方法

其中new DefaultListableBeanFactory对象时,还调用了一个getInternalParentBeanFactory()方法。其中getInternalParentBeanFactory()方法封装在了AbstractRefreshableApplicationContext的父类AbstractApplicationContext

protected DefaultListableBeanFactory createBeanFactory() {
   return new DefaultListableBeanFactory(getInternalParentBeanFactory());
}
复制代码
2-4-2.getInternalParentBeanFactory()`方法

此时代码逻辑在AbstractApplicationContext类中。该方法是先获取容器应用上下文下文对象,如果有则传递给DefaultListableBeanFactory的构造方法。此时获取到的getParent()null,详情请见上篇博客的serParent(parent)部分

protected BeanFactory getInternalParentBeanFactory() {
	return (getParent() instanceof ConfigurableApplicationContext ?
			((ConfigurableApplicationContext) getParent()).getBeanFactory() : getParent());
}
复制代码
2-4-3.实例化DefaultListableBeanFactory容器对象

此时进入DefaultListableBeanFactory构造方法,上一步中getInternalParentBeanFactory()方法获取到的返回值为null所以此时BeanFactory parentBeanFactory值为null。然后就是层层向上调用父类的构造方法。调用顺序:

DefaultListableBeanFactory-->AbstractAutowireCapableBeanFactory-->AbstractBeanFactory

其中执行AbstractAutowireCapableBeanFactory类构造方法时会有一些逻辑。

public DefaultListableBeanFactory(@Nullable BeanFactory parentBeanFactory) {
   super(parentBeanFactory);
}
复制代码
2-4-4.执行AbstractAutowireCapableBeanFactory类的有参构造方法

下面代码中看到在AbstractAutowireCapableBeanFactory构造方法中有两个操作

  1. this()调用了父类构造方法执行了三个ignoreDependencyInterface操作
  2. setParentBeanFactory(parentBeanFactory)此时parentBeanFactory参数为null。这个方法有些双亲委派的思想,而且这个方法具体实现是封装在了AbstractBeanFactory类中

2-4-5. 简单说一下ignoreDependencyInterface方法

ignoreDependencyInterface 的主要功能是忽略给定接口的自动装配功能。

​ 啥意思?就是说你的类实现了被ignoreDependencyInterface()的接口,不能被自动注入到其他的Bean中。比如A类中有个B类的属性,但是B类实现了被ignoreDependencyInterface()的接口,此时你在A类中注入B,Spring时不会给你实例化B类的。

2-4-6. 完成DefaultListableBeanFactory(容器对象)实例化

此时从2-4-1到2-4-6就完成了DefaultListableBeanFactory对象的实例化,即完成了AbstractRefreshableApplicationContextcreateBeanFactory()方法--->回到AbstractRefreshableApplicationContextrefreshBeanFactory()方法中,下一步执行loadBeanDefinitions(beanFactory)方法

类 :AbstractRefreshableApplicationContext
/**
 * 该方法是被final修饰 不允许被子类修改
 * 该方法是 实例化容器 的重要方法
 */
@Override
protected final void refreshBeanFactory() throws BeansException {
   // 若已有 BeanFactory ,销毁它的 Bean 们,并销毁 BeanFactory
   if (hasBeanFactory()) {
      destroyBeans();
      closeBeanFactory();
   }
   try {
      //创建 BeanFactory 容器对象
      DefaultListableBeanFactory beanFactory = createBeanFactory();
      // 设置 BeanFactory 的序列id
      beanFactory.setSerializationId(getId());
      // 定制 BeanFactory 设置相关属性
      customizeBeanFactory(beanFactory);
      //  加载 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);
   }
}

复制代码
2-5(重点)执行AbstractXmlApplicationContext类的loadBeanDefinitions(DefaultListableBeanFactory beanFactory)

该方法是加载/解析Bean元数据信息的方法,此时Spring的容器已经创建好,会把所有的Bean封装成BeanDefiniton(Bean元数据信息)放入容器中。

该方法也有很多个实现,调试代码用的是ClassPathXmlApplicationContext类所以具体实现是在AbstractXmlApplicationContext类中

protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
   // 创建一个 XmlBeanDefinitionReader XML解析器对象 , 需要一个 beanFactory
   XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
   // 在实例化 AbstractRefreshableConfigApplicationContext 时 就已经设置了 Environment 属性
   beanDefinitionReader.setEnvironment(this.getEnvironment());
   // 容器应用上下文对象自身 也是 一个 ResourceLoader 类型
   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);
   /**
    * 装载 BeanDefinitions 最后调用的 XmlBeanDefinitionReader#loadBeanDefinitions()方法
    */
   loadBeanDefinitions(beanDefinitionReader);
}

复制代码

方法中主要操作

  1. new XmlBeanDefinitionReader(beanFactory) 创建一个 XmlBeanDefinitionReader XML解析对象
  2. beanDefinitionReader.setEnvironment(this.getEnvironment()) ,给解析对象设置运行环境对象,此时this.getEnvironment()是有返回值的,详情请看上篇博客的``getEnvironment()方法介绍
  3. beanDefinitionReader.setResourceLoader(this)设置资源加载器,此时的this就是ClassPathXmlApplication对象,因为到现在代码依然在ClassPathXmlApplication的构造方法中。因为ClassPathXmlApplication间接实现了ResourceLoader接口(Spring统一资源加载器,用来获取资源对象Resource这篇博客有详细介绍ResourceLoader
  4. loadBeanDefinitions(beanDefinitionReader) 装载所有BeanDefinitions(Bean的元数据信息对象)
2-5-1: 执行AbstractXmlApplicationContext类的loadBeanDefinitions(XmlBeanDefinitionReader reader)方法

该方法中有两个操作

  1. 获取Resource资源文件,通过getConfigResources()getConfigLocations()方法。其中getConfigLocations()有返回值的(看[Spring IOC 源码调试一]的setConfigLocations(@Nullable String... locations)部分)。
  2. reader.loadBeanDefinitions(configLocations)将加载/解析 xml中bean对象的任务委托给了XmlBeanDefinitionReader对象
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);
   }
}

复制代码
2-5-2:执行AbstractBeanDefinitionReaderloadBeanDefinitions(String... locations)方法

虽然把加载/解析 xml中bean对象的任务委托给了XmlBeanDefinitionReader对象,但是该方法的具体实现被封装在了XmlBeanDefinitionReader父类AbstractBeanDefinitionReader中。

该方法中又是层层调用AbstractBeanDefinitionReaderloadBeanDefinitions重载方法,最后进入到loadBeanDefinitions(String location, @Nullable Set<Resource> actualResources)方法中

public int loadBeanDefinitions(String location, @Nullable Set<Resource> actualResources) throws BeanDefinitionStoreException {
   //初始化 XmlBeanDefinitionReader 时 设置了 setResourceLoader(this)
   ResourceLoader resourceLoader = getResourceLoader();
   if (resourceLoader == null) {
      throw new BeanDefinitionStoreException("Cannot load bean definitions from location [" +    												location + "]: no ResourceLoader available");
   }
   if (resourceLoader instanceof ResourcePatternResolver) {
      // Resource pattern matching available.
      try {
         Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location);
         int count = loadBeanDefinitions(resources);
         if (actualResources != null) {
            Collections.addAll(actualResources, resources);
         }
         if (logger.isTraceEnabled()) {
            logger.trace("Loaded " + count + " bean definitions from location pattern [" + location + "]");
         }
         return count;
      }
      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 count = loadBeanDefinitions(resource);
      if (actualResources != null) {
         actualResources.add(resource);
      }
      if (logger.isTraceEnabled()) {
         logger.trace("Loaded " + count + " bean definitions from location [" + location + "]");
      }
      return count;
   }
}

复制代码

由于篇幅原因loadBeanDefinitions方法到下篇博客继续跟踪......

总结

  1. Spring容器的具体实现对象是DefaultListableBeanFactory

  2. 加载/解析我们配置bean对象的xml文件的类的对象是XmlBeanDefinitionReader对象(这样说可能不太准确,但是解析入口是在该对象中开始的)

欢迎扫码关注

如果喜欢请关注我公众号【程序倾听者】,说出你的故事!我在这里倾听!
文章原文地址

猜你喜欢

转载自juejin.im/post/5ec63456e51d45787e43dcb1