【源码剖析】Spring IOC 详解

shadowLogo

在本人之前的博文中,分别讲述了 Spring框架 的 Ioc功能API调用自主实现流程

作为一款当今各大企业都在使用的 框架,本人的实现相对于真正的 Spring Ioc 来讲,相差甚远

那么,在本篇博文中,本人就来讲解下:在 Spring框架 中,Ioc功能 具体是如何实现的

那么,为了照顾到 初学的同学
在讲解 Spring IOC源码 之前,本人先来回答几个问题:

问题:

为什么要将类实例的创建,交给容器来完成?

答曰:

交由容器来完成,方便我们对这些bean进行管理


为什么容器实现实例的创建,方便我们控制呢?

答曰:

举一个简单的例子:
有一个类的实例对象,在100个类中进行了创建
那么,如果这个对象的 构造函数 不得不做些 改变,我们就需要去改变这100个类的代码
但是,我们交由Spring容器来创建的话,就可以只改动一个类(Bean Configration)的代码


现在,本人就来讲解下 Spring IOC 的相关 源码

在讲解IOC源码之前,本人先来展示下 IOC总体流程图

流程图:

流程图


在Spring中,有一个非常重要的组件 —— BeanFactory

在后续的源码讲解中,我们会发现:
BeanFactory 将会十分频繁地出现,并且在 SpringIOC源码 中 起到 至关重要 的作用:

BeanFactory:

为了之后的讲解,本人先来展示下在 Spring IOC 中,BeanFactory派生类

继承关系:

继承关系


首先,本人来给出一个 简单的API使用案例

API调用:

package edu.youzg.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

import java.util.Date;

/**
 * @Author: Youzg
 * @CreateTime: 2021-03-16 15:17
 * @Description: 带你深究Java的本质!
 */
@Configuration
@ComponentScan("edu.youzg.bean")	// 该包下有两个类:ClassA、ClassB,两个类构成属性的“循环依赖”
public class YouzgConfig {

    @Bean("springIocDate")
    public Date createDate() {
        return new Date();
    }

}

那么,我们根据上面的代码,来看看每一步都干了什么:

上下文 · 可变参构造:

首先,我们来看看 16行代码

public AnnotationConfigApplicationContext(Class<?>... componentClasses) {
    this();
    this.register(componentClasses);
    this.refresh();
}

那么,我们分别来看看,这三个方法都干了什么?

上下文 · 无参构造:

/**
 * 父类构造
 */
public GenericApplicationContext() {
    this.customClassLoader = false;
    this.refreshed = new AtomicBoolean();
    this.beanFactory = new DefaultListableBeanFactory();
}

/**
 * 本类 无参构造
 */
public AnnotationConfigApplicationContext() {
	// 注解扫描器
    this.reader = new AnnotatedBeanDefinitionReader(this);
    // 指定 配置类bean扫描器
    this.scanner = new ClassPathBeanDefinitionScanner(this);
}

可以看到:

无参构造,其实做的只有:
给一些属性赋值,注册了 注解扫描器文件扫描器
这两个 组件,在后面的 getBean()方法 中,将起到重要作用

而我们一层一层点进去查看源码的实现流程,我们就会发现:

通过注册 readerscanner
context 间接地在 bean定义Map 中注册了很多 用于 之后解析配置类实现IOC功能处理器(Processor) 的 bean名称:
注册
(但是,这里仅是 注册bean定义,后续的 getBean操作 才会真正地创造这些处理器的实例)


那么,我们继续看 register()方法 干了什么:

register()方法:

public void register(Class<?>... componentClasses) {
	// 注册所有参数所传bean
	for (Class<?> componentClass : componentClasses) {
		registerBean(componentClass);
	}
}

上面的代码,其实做的事也很简单,
我们一层一层点进去,就会看到如下代码:
注册bean

可以看到:

只是将 API调用时所传配置类的bean 注册到了 beanDefinitionMap


那么,我们继续看下面的方法 —— refresh()方法

refresh方法:

这个方法可了不得,基本上所有的 逻辑,都要在这里实现:

@Override
public void refresh() throws BeansException, IllegalStateException {
	synchronized (this.startupShutdownMonitor) {
		// 准备环境
		prepareRefresh();

		// 获取 bean工厂
		ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

		// 为bean工厂设置各种处理器和参数
		prepareBeanFactory(beanFactory);

		try {
			// Allows post-processing of the bean factory in context subclasses.
			postProcessBeanFactory(beanFactory);

			// 执行bean工厂中 注册的所有后置处理器
			// 将配置类中的所有注解bean进行解析,并存入bean定义map中
			invokeBeanFactoryPostProcessors(beanFactory);

			// 注册 BeanPostProcessor 的实现类
			registerBeanPostProcessors(beanFactory);

			// 国际化
			initMessageSource();

			// 初始化 事件多播器(spring监听器功能 使用)
			initApplicationEventMulticaster();

			// Initialize other special beans in specific context subclasses.
			onRefresh();

			// 事件监听器
			registerListeners();

			// 初始化 所有bean定义Map中的 单例非懒加载bean
			finishBeanFactoryInitialization(beanFactory);

			// 广播 ”上下文容器 初始化完成“事件
			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();
		}
	}
}

那么,在实现 IOC功能 的过程中,我们主要看的方法只有如下:

  • invokeBeanFactoryPostProcessors() 方法
  • registerBeanPostProcessors(beanFactory) 方法

invokeBeanFactoryPostProcessors() 方法:

protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
		PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());

	// 检测LoadTimeWeaver并准备编织(如果在此期间发现)
	//(例如,通过ConfigurationClassPostProcessor注册的@Bean方法)
	if (beanFactory.getTempClassLoader() == null && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
		beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
		beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
	}
}

这里的操作,所实现的功能也很简单:

执行 bean工厂注册的所有后置处理器
也是在这一步中,对 配置类的内容 进行了 解析,解析了 @ComponentScan注解@Bean注解@Component注解


但是,总结起来十分轻巧,我们来看看其具体的 部分实现逻辑

配置类解析 · 具体实现逻辑:

PostProcessorRegistrationDelegate类 · invokeBeanFactoryPostProcessors()方法:

private static void invokeBeanDefinitionRegistryPostProcessors(
		Collection<? extends BeanDefinitionRegistryPostProcessor> postProcessors, BeanDefinitionRegistry registry) {

	for (BeanDefinitionRegistryPostProcessor postProcessor : postProcessors) {
		// 解析配置类,并将用户自定义的bean记录在bean定义Map中
		postProcessor.postProcessBeanDefinitionRegistry(registry);
	}
}

那么,我们来看看具体是怎么解析配置类的:

ConfigurationClassPostProcessor类 · postProcessBeanDefinitionRegistry()方法:

@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
	int registryId = System.identityHashCode(registry);
	if (this.registriesPostProcessed.contains(registryId)) {
		throw new IllegalStateException(
				"postProcessBeanDefinitionRegistry already called on this post-processor against " + registry);
	}
	if (this.factoriesPostProcessed.contains(registryId)) {
		throw new IllegalStateException(
				"postProcessBeanFactory already called on this post-processor against " + registry);
	}
	this.registriesPostProcessed.add(registryId);

	processConfigBeanDefinitions(registry);
}

在这里,我们还是看不到具体流程,
那么,为了节省篇幅,本人来直接跟进到 解析注解 的地方:
注解解析器


那么,我们直接来看上图中,319行的代码的具体实现流程

配置类的解析 —— ConfigurationClassPaser类 :

解析扫描注解

我们跟进 上图中的295行
扫描器的定义
在后面的代码中,对这个扫描器进行了 属性赋值
属性赋值

之后,进行了 真正的 扫描操作
扫描

那么,一直跟进去,就会看到下图:
满足规则

但是,在这里,解析出来的result,是指定包路径下的所有 .java文件的信息,
(其实是编译后目录 target/out/bin目录 下的 .class文件信息,但我们一般日常开发,是不会接触到这么深的层次,
因此,我们就简单理解为 .java文件 信息即可)
result

之后,在 扫描到的所有.java文件 中,筛选出 bean的信息
判断

我们跟进去:
检测Component

一直跟进去,就会看到在 检验注解
检验注解

在之后,只会将 解析出来的bean信息,存储在 bean定义Map 中:
真正解析

接着向下执行,层层返回,我们可以看到,只解析到了 合法的bean
解析结果
向下执行,就会对解析出来的bean,根据 注解的属性配置,进行 bean的属性配置
属性赋值

之后,对解析到的 真正的bean的信息,进行一些列操作,最终将信息放入了 bean定义Map 中:
存入bean定义Map

至此,自定义的bean信息 就全部 解析并存储 到了 bean定义Map 中!


那么,自定义bean的实例,在什么时候会被创建呢?
答曰

还是在 refresh()方法
finishBeanFactoryInitialization(beanFactory); 这一句会被 初始化成功

现在我们来看下,finishBeanFactoryInitialization()方法 的源码:

自定义bean的 实例化 —— finishBeanFactoryInitialization()方法:

// 初始化 自定义单例非懒记载bean
protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
 
   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));
   }
 
   // Register a default embedded value resolver if no bean post-processor
   // (such as a PropertyPlaceholderConfigurer bean) registered any before:
   // at this point, primarily for resolution in annotation attribute values.
   if (!beanFactory.hasEmbeddedValueResolver()) {
      beanFactory.addEmbeddedValueResolver(new StringValueResolver() {
         @Override
         public String resolveStringValue(String strVal) {
            return getEnvironment().resolvePlaceholders(strVal);
         }
      });
   }
 
   String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false);
   for (String weaverAwareName : weaverAwareNames) {
      getBean(weaverAwareName);
   }
 
   // Stop using the temporary ClassLoader for type matching.
   beanFactory.setTempClassLoader(null);
 
   // 冻结配置,防止 bean 定义解析、加载、注册
   beanFactory.freezeConfiguration();
 
   // 初始化 自定义非懒加载单例bean 的实例
   beanFactory.preInstantiateSingletons();
}

那么,根据上面代码的注释,我们也能知道:

真正的 实例化bean逻辑preInstantiateSingletons()方法


preInstantiateSingletons()方法:

@Override
public void preInstantiateSingletons() throws BeansException {
   if (this.logger.isDebugEnabled()) {
      this.logger.debug("Pre-instantiating singletons in " + this);
   }
 
   List<String> beanNames = new ArrayList<String>(this.beanDefinitionNames);
 
   // 触发所有的非懒加载的 singleton beans 的初始化操作
   for (String beanName : beanNames) {
      RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
 
      // 判断当前bean的合法性
      if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
         // 判断当前自定义bean,是否是 工厂bean
         if (isFactoryBean(beanName)) {
            /*
            	FactoryBean 的话,在 beanName 前面加上 ‘&’ 符号
            	因为工厂bean的真实bean定义,在bean定义Map中,是以”&工厂bean“作为beanName的
            */
            final FactoryBean<?> factory = (FactoryBean<?>) getBean(FACTORY_BEAN_PREFIX + beanName);
            // 判断当前 FactoryBean 是否是 SmartFactoryBean 的实现,此处忽略,直接跳过
            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 {
            // 实例化 普通自定义bean
            getBean(beanName);
         }
      }
   }
 
 
   // 到这里
   // 所有的非懒加载的单例bean 已经完成了实例化
   // 之后的操作,都是用于实现 ”回掉函数“,我们一般用不到,这里可以当作结束了
   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();
         }
      }
   }
}

上面的代码,也十分秃然!
但是,其实我们仔细去看,这个方法无论是哪个分支,只要是以 实例化bean 为目的的,都会执行 getBean() 这个方法


那么,本人现在来讲解下 getBean()方法

bean实例 的获取 —— getBean()方法:

还是Spring之前的作风,包装了一层
真正的操作方法,都是以 doXxx 格式存在的!
getBean实际

那么,我们来跟进去:

实际操作 —— doGetBean()方法:

/**
 * doGetBean() 不止用于 创建容器中的bean
 * 在我们通过beanName进行获取bean实例时,也会调用此方法
 * (已经初始化过了就从容器中直接返回,否则就先初始化再返回)
 */
@SuppressWarnings("unchecked")
protected <T> T doGetBean(
      final String name, final Class<T> requiredType, final Object[] args, boolean typeCheckOnly)
      throws BeansException {
   // beanName转换,以便 别名、工厂bean 的 实例创建
   final String beanName = transformedBeanName(name);
 
   // 定义返回值
   Object bean; 
 
   // 检查当前bean 是否已被创建
   Object sharedInstance = getSingleton(beanName);
 
   // args不为null,则 创建 bean实例
   if (sharedInstance != null && args == null) {
      if (logger.isDebugEnabled()) {
         if (isSingletonCurrentlyInCreation(beanName)) {
            logger.debug("...");
         }
         else {
            logger.debug("Returning cached instance of singleton bean '" + beanName + "'");
         }
      }
      /*
      	如果是普通 bean 的话,直接返回 sharedInstance,
      	如果是 FactoryBean 的话,返回 创建的实例对象
      */
      bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
   }
 
   else {
      if (isPrototypeCurrentlyInCreation(beanName)) {
         // 判断当前bean的实例,是否正在被创建
         throw new BeanCurrentlyInCreationException(beanName);
      }
 
      // 检查一下这个 BeanDefinition 在容器中是否存在
      BeanFactory parentBeanFactory = getParentBeanFactory();
      if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
         // 如果当前容器不存在这个 BeanDefinition,在父容器中查找
         String nameToLookup = originalBeanName(name);
         if (args != null) {
            // 返回父容器的查询结果
            return (T) parentBeanFactory.getBean(nameToLookup, args);
         }
         else {
            // No args -> delegate to standard getBean method.
            return parentBeanFactory.getBean(nameToLookup, requiredType);
         }
      }
 
      if (!typeCheckOnly) {
         // typeCheckOnly 为 false,将当前 beanName 放入一个 alreadyCreated 的 Set 集合中。
         markBeanAsCreated(beanName);
      }
 
	  // 创建bean实例
      try {
         final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
         checkMergedBeanDefinition(mbd, beanName, args);
 
         // 先初始化依赖的所有 Bean,这个很好理解。
         // 注意,这里的依赖指的是 depends-on 中定义的依赖
         /*
			初始化 所有depends-on 中定义的依赖的 bean定义
		  */
         String[] dependsOn = mbd.getDependsOn();
         if (dependsOn != null) {
            for (String dep : dependsOn) {
               // 检查是否有循环依赖,此处的循环依赖是不能发生的(此处是直接初始化,并没有设置 “三级缓存”)
               if (isDependent(beanName, dep)) {
                  throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                        "Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
               }
               // 注册 依赖关系
               registerDependentBean(dep, beanName);
               // 实例化 被依赖bean
               getBean(dep);
            }
         }
 
 		/*
 			实例化 目标bean
 		*/
         if (mbd.isSingleton()) {
            sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() {
               @Override
               public Object getObject() throws BeansException {
                  try {
                     // 执行创建 Bean,详情后面再说
                     return createBean(beanName, mbd, args);
                  }
                  catch (BeansException ex) {
                     destroySingleton(beanName);
                     throw ex;
                  }
               }
            });
            bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
         }
 
         // 创建 prototype 的实例
         else if (mbd.isPrototype()) {
            // It's a prototype -> create a new instance.
            Object prototypeInstance = null;
            try {
               beforePrototypeCreation(beanName);
               // 执行创建 Bean
               prototypeInstance = createBean(beanName, mbd, args);
            }
            finally {
               afterPrototypeCreation(beanName);
            }
            bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
         }
 
         // 如果不是 singleton 和 prototype 的话,需要委托给相应的实现类来处理
         else {
            String scopeName = mbd.getScope();
            final Scope scope = this.scopes.get(scopeName);
            if (scope == null) {
               throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");
            }
            try {
               Object scopedInstance = scope.get(beanName, new ObjectFactory<Object>() {
                  @Override
                  public Object getObject() throws BeansException {
                     beforePrototypeCreation(beanName);
                     try {
                        // 执行创建 Bean
                        return createBean(beanName, mbd, args);
                     }
                     finally {
                        afterPrototypeCreation(beanName);
                     }
                  }
               });
               bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
            }
            catch (IllegalStateException ex) {
               throw new BeanCreationException(beanName,
                     "Scope '" + scopeName + "' is not active for the current thread; consider " +
                     "defining a scoped proxy for this bean if you intend to refer to it from a singleton",
                     ex);
            }
         }
      }
      catch (BeansException ex) {
         cleanupAfterBeanCreationFailure(beanName);
         throw ex;
      }
   }
 
   // 最后,检查类型是否满足要求
   if (requiredType != null && bean != null && !requiredType.isInstance(bean)) {
      try {
         return getTypeConverter().convertIfNecessary(bean, requiredType);
      }
      catch (TypeMismatchException ex) {
         if (logger.isDebugEnabled()) {
            logger.debug("Failed to convert bean '" + name + "' to required type '" +
                  ClassUtils.getQualifiedName(requiredType) + "'", ex);
         }
         throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
      }
   }
   return (T) bean;
}

上面的代码看的人头痛!
无法接受

但是,Spring IOC 所有的 实例化bean的操作,都是在本方法中进行实现的

在这里,有一个非常重要的知识点 —— 循环依赖 的解决
那么,为了同学们能够顺利过一遍逻辑,本人就在下文来详细地讲下 Spring IOC循环依赖 解决


API获取bean:

那么,我们就来讲解下 getBean()方法

getBean
一直跟进去:
跟进去
那么,兜兜转转,又回来了!
相信在这里,同学们应该能明白 IOC的基本流程了!


接下来,本人就来讲解下 Spring IOC循环依赖解决方式

循环依赖 的解决:

在讲解源码之前,本人先来讲解下 一个很重要的名词 —— 三级缓存

三级缓存:

相信同学们一旦搜索 Spring循环依赖,就会发现 三级缓存 这个名词十分瞩目

但是,很少有人能解释的通什么是 三级缓存
这就经常会给我们造成心理上的“畏惧”

那么,本人来展示下 相关的源码:

/** 
	(一级缓存)单例对象的缓存:
		beanName 到 bean实例 的映射
		用于保存 实例化、注入、初始化完成 的bean实例
 */
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);

/**
	(二级缓存)早期单例对象的缓存:
		beanName 到 bean实例(未注入、初始化) 的映射
		用于保存 实例化完成(未注入、初始化) 的bean实例
*/
private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);

/**
	(三级缓存)单例工厂的缓存:
		beanName 到 ObjectFactory 的映射
		用于保存bean创建工厂,以便于后面扩展有机会创建代理对象
*/
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);

可以看到:

所谓的 三级缓存,不过就是三个Map

那么,为什么要称之为 三级缓存 呢?

其实我们字字对译,也很通俗易懂
三级,就是在不同阶段
缓存,就是 内存中 存取数据的 数据结构
那么,既然要涉及存取,就要用到 双列集合
综合所有方面的考虑,Map无疑非常合适,因此取名为 三级缓存

那么,为什么要按照本人上文中所讲解的顺序进行排名呢?
答曰:

在之后的源码中,我们能发现:
我们获取一个bean的实例对象时,其实是 按照 一级缓存 -> 二级缓存 -> 三级缓存顺序 进行获取的


那么,Spring又是怎么通过 三级缓存 来解决 循环依赖 问题的呢?
我们来 回顾下 doGetBean()方法部分源码

再见 doGetBean():

由于 doGetBean()方法 的源码,本人在上文中已经很清楚地展示了

那么,在这里,本人就通过源码截图的形式,来讲解下 Spring IOC 中,循环依赖 的解决:

首先,我们直接跳转到 初次获取目标bean实例 的那行代码:

初次获取 目标bean实例:

初次获取
跟进去:
跟进去
继续跟进去:
一级缓存
我们可以看到:

当我们想要获取一个bean的实例时,会先去 一级缓存 中尝试获取
一级缓存 中没有取到目标bean实例,就会去 二级缓存 中去获取 未实例化完成的目标bean实例
二级缓存 中不存在 未实例化完成的目标bean实例,再去 三级缓存 中获取 目标bean的实例化工厂后置处理器

不管我们是 创建bean实例,还是 通过beanName获取bean实例,我们都会优先调用这个方法

三级缓存 的排名,就是由此而来!


我们继续debug:
debug
这里的代码,只是为了保证在 一个线程创建bean实例 的过程中,其 元数据 不会被其它线程所更改


继续向下debug,就会到 创建目标bean实例 的代码块:
创建目标bean实例


我们来看下上图中的 321行代码执行流程
321
向下debug:
标记正在创建
可以看到:

在 实例化目标bean 之前,Spring会将 目标bean 存储到 正在创建列表
以便我们为一个bean进行属性注入时,能够 将重复bean识别避免重复创建bean实例
这里也是 循环依赖 的出口,只有标记了 当前bean的实例正在被创建,我们才能 发现并处理 循环依赖


继续看 之后的代码,会执行参数所穿的 “钩子函数”:
钩子
继续向下执行,会执行到 createBean()方法
判断AOP
继续向下debug:
返回
我们跟进去,来看看具体的 创建目标bean本类实例 的流程:
创建实例
继续跟进去 557行代码
执行
继续跟进去:
执行
点进 1312行代码
构造
继续跟进去,就没有必要了,
因为,在这里已经通过使用 发射机制 调用 目标bean空参构造 进行了 bean实例化
(注意,这里的 目标bean实例,是 没属性注入的,用专业术语来讲,就是 纯净的


那么,我们将这个结果返回,来执行之后的代码:
包装结果


继续返回,向下执行:
执行
跟进 588行
缓存逻辑

可以看到:

当我们获取到 目标bean实例化纯净对象 后,
就会对缓存做如下处理:
存入 三级缓存
二级缓存 中删除

这样做是为了 处理 循环依赖


继续向下执行:
继续
可以看到:

之后的代码,就要执行 属性注入 的相关操作了


那么,最后,本人来通过一张 流程图,来形象地概括下 循环依赖解决流程

解决流程:

解决流程

看完上图之后,相信有同学还会有这样的问题:

一级缓存三级缓存 已经够用了,为什么还要 二级缓存 呢?

二级缓存 的作用:

假设我们只用 一级缓存三级缓存 进行IOC实现
那么,当 A依赖B、C,B、C分别都依赖 A 这种情况出现时,
B和C所注入的A,都是通过 三级缓存 获取的 A工厂,所注入的就不是 同一个A对象

所以,二级缓存 的主要作用,就是为了保证:

循环依赖 的过程中,注入的对象都是同一个


那么,讲到这里,Spring IOC基本实现流程 就讲解完毕了!
当然,本人讲解的仅是 很小一些规模注解式实现
但是,其实其它注解和属性的解析流程,和上面分析都是类似的,都是通过 readerscanner 注册时,所注册的各个 processor 去解析
并且一些很牛的功能 —— AOP国际化监听器 等功能的实现,都是在 Spring IOC 中实现的
有兴趣的小伙伴请自行阅读源码


那么,本人在这里来做几点小总结:

总结:

设计模式:

首先,我们读了这么长的源码,仔细去品的话,会发现有很多 看上去很 “繁琐” 的代码
(比如:本人说为了节省篇幅,直接定位到执行操作的代码处)

这就是运用到了很多的 设计模式,比如:

  • 责任链模式
  • 门面模式
  • 代理模式
  • 工厂模式
  • 单例模式
  • 策略模式
  • 装饰器模式
  • 发布订阅模式
  • ...

这些 设计模式 的运用,以及很多 设计原则 的符合
使得我们这些 “编程菜鸟” 觉得Spring的代码很 “臃肿”
这种很 graceful 的代码设计,我们还是需要仔细去


反射机制:

通过我们阅读 Spring IOC 的源码,我们也能发现:

创建bean实例,所运用到的就是 反射机制

这也是Java所提供给我们API调用者的一个非常强悍的 工具
因此,我们学习源码,也会发现 业务开发中几乎用不到的 反射机制 在这里会 大放异彩


循环依赖 与 三级缓存:

我们若是 在网上去阅读一些别人的博文,或是 看一些教程视频,就会发现很多人在说:

只要创建bean实例对象,就会使用到 三级缓存

当然,这样讲是正确的!
但是,却回答的很模糊

我们若是跟着代码debug一次,就会发现:

只有依赖别的bean,三级缓存 才会被全部使用到
我们创建的对象,若是并不依赖其它bean,那么只会使用到 一级缓存

因此,对于别人讲解的知识点,我们能自己验证的,就最好验证一遍!


但是,并不是所有 循环依赖,Spring都能帮我们解决:

无法解决的 循环依赖:

无法解决


还有很重要的一点,注解式配置文件式加载流程还是有一些的区别的:

配置文件式 · 源码剖析:

《Spring IOC 源码剖析 (配置文件式)》


参考文章:

《Spring 如何解决循环依赖的问题》
《Spring IOC 源码剖析 (配置文件式)》
《Spring 是如何解决循环依赖的?》

posted @ 2021-03-20 00:38  在下右转,有何贵干  阅读(256)  评论(0编辑  收藏  举报