前言

上一篇我们整理了IoC相关的几个类体系架构,本篇从一小段代码开始Debug,看Spring具体的实现。

源码分析

从容器获取一个单例的Bean:

  1. public static void main(String[] args) {
  2. // 入口,加载xml配置,刷新容器,见#1
  3. ApplicationContext context = new ClassPathXmlApplicationContext("spring/spring-ioc.xml");
  4. // 单例下这个getBean()实际上是从缓存中获取的
  5. StudentB studentB1 = (StudentB) context.getBean("studentB");
  6. StudentB studentB2 = (StudentB) context.getBean("studentB");
  7. // 输出的结果是一样的
  8. System.out.println("studentB1: " + studentB1);
  9. System.out.println("studentB2: " + studentB2);
  10. }

调用方法:org.springframework.context.support.AbstractApplicationContext#refresh

  1. // #1 完成IoC容器的创建及初始化
  2. public void refresh() throws BeansException, IllegalStateException {
  3. synchronized (this.startupShutdownMonitor) {
  4. // 预刷新处理,刷新上下文,设置启动数据,初始化环境数据
  5. prepareRefresh();
  6. // 重点,刷新初始化容器,完成BeanDefinition注册,见#2
  7. ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
  8. // 对IoC容器进行一些预处理,设置一些公共属性
  9. prepareBeanFactory(beanFactory);
  10. try {
  11. // Allows post-processing of the bean factory in context subclasses.
  12. postProcessBeanFactory(beanFactory);
  13. // 对BeanDefinition进行处理
  14. invokeBeanFactoryPostProcessors(beanFactory);
  15. // 注册BeanPostProcessor后置处理器
  16. registerBeanPostProcessors(beanFactory);
  17. // 初始化消息源
  18. initMessageSource();
  19. // 初始化应用事件广播器
  20. initApplicationEventMulticaster();
  21. // 初始化一些特殊的bean
  22. onRefresh();
  23. // 检测监听器并注册
  24. registerListeners();
  25. // 重点, 实例化所有剩余的单例bean(非懒加载方式)
  26. // Bean的IoC、DI都是发生在此步骤
  27. finishBeanFactoryInitialization(beanFactory);
  28. // 完成刷新,发布对应的事件
  29. finishRefresh();
  30. }
  31. catch (BeansException ex) {
  32. // 省略代码...
  33. }
  34. finally {
  35. // 省略代码...
  36. }
  37. }
  38. }

注册BeanDefinition

调用方法:org.springframework.context.support.AbstractApplicationContext#obtainFreshBeanFactory

  1. // #2 刷新容器
  2. protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
  3. // 主要是通过该方法完成IoC容器的刷新,见#3
  4. refreshBeanFactory();
  5. ConfigurableListableBeanFactory beanFactory = getBeanFactory();
  6. // 省略代码...
  7. return beanFactory;
  8. }

调用方法:org.springframework.context.support.AbstractRefreshableApplicationContext#refreshBeanFactory

  1. // #3 刷新IoC容器
  2. protected final void refreshBeanFactory() throws BeansException {
  3. // 如果已经有IoC容器,则销毁
  4. if (hasBeanFactory()) {
  5. destroyBeans();
  6. closeBeanFactory();
  7. }
  8. try {
  9. // 创建默认的IoC容器 DefaultListableBeanFactory
  10. DefaultListableBeanFactory beanFactory = createBeanFactory();
  11. beanFactory.setSerializationId(getId());
  12. // 设置工厂的属性,是否允许BeanDefinition覆盖和是否允许循环依赖
  13. customizeBeanFactory(beanFactory);
  14. // 加载BeanDefinition,这个抽象方法,具体的实现让具体的子类完成,见#4
  15. loadBeanDefinitions(beanFactory);
  16. synchronized (this.beanFactoryMonitor) {
  17. this.beanFactory = beanFactory;
  18. }
  19. }
  20. catch (IOException ex) {
  21. // 省略代码...
  22. }
  23. }

调用方法:org.springframework.context.support.AbstractXmlApplicationContext#loadBeanDefinitions

  1. // #4 读取xml类型的资源文件
  2. protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
  3. // 获取资源路径
  4. Resource[] configResources = getConfigResources();
  5. if (configResources != null) {
  6. // XML Bean读取器调用其父类AbstractBeanDefinitionReader读取定位的资源
  7. reader.loadBeanDefinitions(configResources);
  8. }
  9. // 获取资源路径,我们这里是:spring/spring-ioc.xml
  10. String[] configLocations = getConfigLocations();
  11. if (configLocations != null) {
  12. // XML Bean读取器调用其父类AbstractBeanDefinitionReader读取定位的资源
  13. // 见#5
  14. reader.loadBeanDefinitions(configLocations);
  15. }
  16. }

调用方法:org.springframework.beans.factory.xml.XmlBeanDefinitionReader#loadBeanDefinitions

  1. // #5 经过一系列的调用,包装,在这里开始解析xml文件获得BeanDefinition
  2. public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
  3. // 省略代码...
  4. try {
  5. // 将资源文件转为流
  6. InputStream inputStream = encodedResource.getResource().getInputStream();
  7. try {
  8. InputSource inputSource = new InputSource(inputStream);
  9. if (encodedResource.getEncoding() != null) {
  10. inputSource.setEncoding(encodedResource.getEncoding());
  11. }
  12. // do开头的方法是真正执行过程,开始解析,见#6
  13. return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
  14. }
  15. // 省略代码...
  16. }
  17. // 省略代码...
  18. }

调用方法:org.springframework.beans.factory.xml.XmlBeanDefinitionReader#doLoadBeanDefinitions

  1. // #6 开始解析加载
  2. protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
  3. throws BeanDefinitionStoreException {
  4. try {
  5. // 通过DOM4J加载解析XML文件,最终形成Document对象
  6. Document doc = doLoadDocument(inputSource, resource);
  7. // 通过对Document对象的操作,完成BeanDefinition的加载和注册工作,见#7
  8. return registerBeanDefinitions(doc, resource);
  9. }
  10. // 省略代码...
  11. }

调用方法:org.springframework.beans.factory.xml.XmlBeanDefinitionReader#registerBeanDefinition

  1. // #7 又经过一系列的处理,会在添加到一个map中
  2. public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
  3. throws BeanDefinitionStoreException {
  4. BeanDefinition oldBeanDefinition;
  5. oldBeanDefinition = this.beanDefinitionMap.get(beanName);
  6. if (oldBeanDefinition != null) {
  7. // 省略代码...
  8. // 如果是重复的BeanDefinition的一系列处理判断
  9. }
  10. else {
  11. // 不是第一个BeanDefinition的处理逻辑
  12. // 但是我们这里没有标记,所以还是会走下面逻辑
  13. if (hasBeanCreationStarted()) {
  14. // 省略代码...
  15. }
  16. // 如果是第一个BeanDefinition的处理逻辑
  17. else {
  18. // 会存进一个map中,beanName是key,beanDefinition是value
  19. // beanName:就是bean的名称,我们这里是studentB
  20. // beanDefinition:储存着一个bean的详细信息,如下图
  21. this.beanDefinitionMap.put(beanName, beanDefinition);
  22. this.beanDefinitionNames.add(beanName);
  23. this.manualSingletonNames.remove(beanName);
  24. }
  25. this.frozenBeanDefinitionNames = null;
  26. }
  27. // 省略代码...
  28. }

image.png
BeanDefinition中的bean信息数据结构

创建Bean

前面已经完成了Bean信息的加载,接下来看下Bean是如何创建的,这里有个经典的循环依赖问题,也通过源码看Spring是如何处理的。

还是调用这个方法:org.springframework.context.support.AbstractApplicationContext#refresh

  1. // 完成IoC容器的创建及初始化
  2. public void refresh() throws BeansException, IllegalStateException {
  3. synchronized (this.startupShutdownMonitor) {
  4. // 省略代码...
  5. try {
  6. // 省略代码...
  7. // 重点, 实例化所有剩余的单例bean(非懒加载方式)
  8. // Bean的IoC、DI都是发生在此步骤
  9. finishBeanFactoryInitialization(beanFactory);
  10. }
  11. catch (BeansException ex) {
  12. // 省略代码...
  13. }
  14. finally {
  15. // 省略代码...
  16. }
  17. }
  18. }

调用方法:org.springframework.beans.factory.support.AbstractBeanFactory#doGetBean

  1. protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
  2. @Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
  3. // 获取bean名称
  4. final String beanName = transformedBeanName(name);
  5. Object bean;
  6. // 从缓存或单例工厂中获取单例bean,见##1
  7. Object sharedInstance = getSingleton(beanName);
  8. //如果获取到单例bean,则走下面代码
  9. if (sharedInstance != null && args == null) {
  10. // 如果取出来的Bean实例是FactoryBean的Bean实例
  11. // 则需要从FactoryBean实例中产生一个对象实例。
  12. // FactoryBean可以对某类复杂Bean生成对象,BeanFactory则是任意对象
  13. bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
  14. }
  15. //如果没有获取到单例bean,则走下面代码
  16. else {
  17. // 如果是原型模式的Bean发生循环引用,不处理,直接抛出异常
  18. if (isPrototypeCurrentlyInCreation(beanName)) {
  19. throw new BeanCurrentlyInCreationException(beanName);
  20. }
  21. // 省略代码...
  22. try {
  23. // 获取要实例化的bean的BeanDefinition对象
  24. final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
  25. // 省略代码...
  26. // 如果是单例的Bean
  27. if (mbd.isSingleton()) {
  28. sharedInstance = getSingleton(beanName, () -> {
  29. try {
  30. // 创建单例Bean的主要方法,见##2
  31. return createBean(beanName, mbd, args);
  32. }
  33. catch (BeansException ex) {
  34. // 省略代码...
  35. }
  36. });
  37. // 完成 FactoryBean 的相关处理,并用来获取 FactoryBean 的处理结果
  38. bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
  39. }
  40. // 如果是原型的Bean
  41. else if (mbd.isPrototype()) {
  42. // 省略代码...
  43. }
  44. // 处理request或session的Bean
  45. else {
  46. // 省略代码...
  47. }
  48. }
  49. // 省略代码...
  50. }
  51. // 省略代码...
  52. return (T) bean;
  53. }

调用方法:org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#getSingleton

  1. // ##1,一级没有去二级拿,二级没有去三级拿,三级拿完移除并添加到二级中
  2. protected Object getSingleton(String beanName, boolean allowEarlyReference) {
  3. // 从一级缓存中获取单例对象
  4. Object singletonObject = this.singletonObjects.get(beanName);
  5. // isSingletonCurrentlyInCreation() :
  6. // 判断当前单例bean是否正在创建中,也就是没有初始化完成
  7. // 比如A的构造器依赖了B对象所以得先去创建B对象,或者在A的populateBean过程中依赖了B对象,得先去创建B对象
  8. // 这时的A就是处于创建中的状态。
  9. if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
  10. synchronized (this.singletonObjects) {
  11. // 从二级缓存中获取单例bean
  12. singletonObject = this.earlySingletonObjects.get(beanName);
  13. // allowEarlyReference():
  14. // 是否允许从singletonFactories中通过getObject拿到对象
  15. if (singletonObject == null && allowEarlyReference) {
  16. // 从三级缓存中获取单例bean
  17. ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
  18. if (singletonFactory != null) {
  19. // 通过单例工厂获取单例bean
  20. singletonObject = singletonFactory.getObject();
  21. // 从三级缓存移动到了二级缓存
  22. this.earlySingletonObjects.put(beanName, singletonObject);
  23. this.singletonFactories.remove(beanName);
  24. }
  25. }
  26. }
  27. }
  28. return singletonObject;
  29. }

调用方法:org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#doCreateBean

  1. // ##2 完成Bean实例的创建(实例化、填充属性、初始化)
  2. protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
  3. throws BeanCreationException {
  4. // 省略代码...
  5. // bean初始化第一步:默认调用无参构造实例化Bean
  6. // 构造参数依赖注入,就是发生在这一步
  7. if (instanceWrapper == null) {
  8. instanceWrapper = createBeanInstance(beanName, mbd, args);
  9. }
  10. // 实例化后的Bean对象
  11. final Object bean = instanceWrapper.getWrappedInstance();
  12. Class<?> beanType = instanceWrapper.getWrappedClass();
  13. if (beanType != NullBean.class) {
  14. mbd.resolvedTargetType = beanType;
  15. }
  16. // 省略代码...
  17. // 如果是单例且允许循环依赖且该Bean还在创建中
  18. boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
  19. isSingletonCurrentlyInCreation(beanName));
  20. // 如果需要提前暴露单例Bean,则将该Bean放入三级缓存中
  21. if (earlySingletonExposure) {
  22. // 将刚创建的bean放入三级缓存中singleFactories(key是beanName,value是FactoryBean)
  23. addSingletonFactory(beanName,
  24. () -> getEarlyBeanReference(beanName, mbd, bean));
  25. }
  26. // Initialize the bean instance.
  27. Object exposedObject = bean;
  28. try {
  29. // bean初始化第二步:填充属性(DI发生在此步骤)
  30. populateBean(beanName, mbd, instanceWrapper);
  31. // bean初始化第三步:调用初始化方法,完成bean的初始化操作
  32. exposedObject = initializeBean(beanName, exposedObject, mbd);
  33. }
  34. // 省略代码...
  35. return exposedObject;
  36. }

循环依赖

image.png
图片来源:《Spring源码深度解析》

什么是循环依赖?

循环依赖就是循环引用,两个或多个bean相互之间的持有对方。例如A依赖B,而B又依赖A,最终形成闭环,并且只有单例Bean的循环依赖可以通过setter注入方式来解决,构造注入无法解决,其他类型的Bean更无法处理

循环依赖处理

先看看一个Bean实例化的三个步骤:

  1. createBeanInstance 调用对象的构造方法实例化对象,是“残缺的”
  2. populateBean 对象属性填充
  3. initializeBean 对象初始化

循环依赖发生在第2步,因此我们也在第2步来处理,处理的策略是利用缓存。例如对象A依赖对象B,对象B又依赖对象A,那么当对象A实例化后进行属性填充,需要填充对象B,这时又去实例化B,填充B对象的属性发现要实例化A,但此时Spring会先去缓存中查找,而缓存又分为三级缓存。

一级缓存:singletonObject,缓存单例Bean
二级缓存:earlySingletonObjects,缓存实例化后的Bean,提前曝光
三级缓存:singletonFactories,缓存的是单例对象工厂,对Bean做beanPostProcessor后置处理,处理后在添加到二级缓存中并同时删除三级缓存中的数据,它才是真正处理循环依赖的。

在看完org.springframework.beans.factory.support.AbstractBeanFactory#doGetBean就会明白为什么只能处理单例的setter循环依赖,因为Bean实例化第一步就是调用构造器来实例化对象,而field初始化是可以延迟的。

参考资料

请你相信我所说的都是错的