Spring 三级缓存解决循环依赖

导读:本篇文章讲解 Spring 三级缓存解决循环依赖,希望对大家有帮助,欢迎收藏,转发!站点地址:www.bmabk.com

引言

概述: Spring Bean 创建源码分析系列

【1】Spring Bean 的实例化过程源码解析
【2】Spring 依赖注入(DI) 源码解析
【3】Spring 三级缓存解决循环依赖

1 工程介绍

在这里插入图片描述

1.1 StudentService

@Service
public class StudentService {

    @Autowired
    private TeacherService teacherService;

    public StudentService(){

        System.out.println("StudentService invoke NoArgsConstructor");

    }

}

1.2 TeacherService

@Service
public class TeacherService {

    @Autowired
    private StudentService studentService;

    public TeacherService(){

        System.out.println("TeacherService invoke NoArgsConstructor");

    }

}

1.3 applicationContext.xml

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="
	http://www.springframework.org/schema/beans
	http://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context.xsd"
       default-lazy-init="false">

    <context:component-scan base-package="com.rosh.service"/>


</beans>

1.4 RoshTest

public class RoshTest {

    @Test
    public void mainTest(){
        ClassPathXmlApplicationContext applicationContext=new ClassPathXmlApplicationContext("applicationContext.xml");
        applicationContext.close();

    }

}

1.5 运行结果

在这里插入图片描述

2 三级缓存介绍

在这里插入图片描述

2.1 一级缓存

介绍: 当一个bean经过 创建实例、依赖注入、bean初始化,会存入一级缓存,我们说的单例池。

#创建实例
createBeanInstance(beanName, mbd, args)
#依赖注入
populateBean(beanName, mbd, instanceWrapper);
#bean的初始化
initializeBean(beanName, exposedObject, mbd);

描述: DefaultSingletonBeanRegistry getSingleton 方法。
在这里插入图片描述

public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
		Assert.notNull(beanName, "Bean name must not be null");
		synchronized (this.singletonObjects) {


			/**
			 * 【1】从一级缓存中获取,如果一级缓存中存在,则直接返回bean
			 */
			Object singletonObject = this.singletonObjects.get(beanName);


			if (singletonObject == null) {
				if (this.singletonsCurrentlyInDestruction) {
					throw new BeanCreationNotAllowedException(beanName,
							"Singleton bean creation not allowed while singletons of this factory are in destruction " +
							"(Do not request a bean from a BeanFactory in a destroy method implementation!)");
				}
				if (logger.isDebugEnabled()) {
					logger.debug("Creating shared instance of singleton bean '" + beanName + "'");
				}

				/**
				 * 【2】 把beanName添加到singletonsCurrentlyInCreation Set容器中,在这个集合里面的bean都是正在实例化的bean
				 */
				beforeSingletonCreation(beanName);


				boolean newSingleton = false;
				boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
				if (recordSuppressedExceptions) {
					this.suppressedExceptions = new LinkedHashSet<>();
				}
				try {
					/**
					 *【3】 创建对象,调用AbstractAutowireCapableBeanFactory createBean
					 *
					 * 当调用singletonFactory.getObject();获取到对象时,说明对象已经完全创建成功
					 *
					 */
					singletonObject = singletonFactory.getObject();
					newSingleton = true;
				}
				catch (IllegalStateException ex) {
					// Has the singleton object implicitly appeared in the meantime ->
					// if yes, proceed with it since the exception indicates that state.
					singletonObject = this.singletonObjects.get(beanName);
					if (singletonObject == null) {
						throw ex;
					}
				}
				catch (BeanCreationException ex) {
					if (recordSuppressedExceptions) {
						for (Exception suppressedException : this.suppressedExceptions) {
							ex.addRelatedCause(suppressedException);
						}
					}
					throw ex;
				}
				finally {
					if (recordSuppressedExceptions) {
						this.suppressedExceptions = null;
					}

					/**
					 * 【4】 创建成功后,真在创建的bean里面移除该bean
					 */
					afterSingletonCreation(beanName);
				}
				if (newSingleton) {
					/**
					 *  【5】当对象完成创建时,把对象放入singletonObjects缓存中,bean完成创建时放入一级缓存
					 */
					addSingleton(beanName, singletonObject);
				}
			}
			return singletonObject;
		}
	}

描述: 当获取到创建的对象时,会将对象存入一级缓存(单例池),并且移除二级缓存、三级缓存。
在这里插入图片描述
在这里插入图片描述

2.2 三级缓存

描述: 存放仅完成创建实例的对象,该对象还没有进行依赖注入、初始化操作。AbstractAutowireCapableBeanFactory doCreateBean 方法:

protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
			throws BeanCreationException {

		// Instantiate the bean.
		BeanWrapper instanceWrapper = null;
		if (mbd.isSingleton()) {
			instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
		}
		if (instanceWrapper == null) {

			/**
 			 * 【1】创建实例
			 */
			instanceWrapper = createBeanInstance(beanName, mbd, args);
		}
		Object bean = instanceWrapper.getWrappedInstance();
		Class<?> beanType = instanceWrapper.getWrappedClass();
		if (beanType != NullBean.class) {
			mbd.resolvedTargetType = beanType;
		}

		// Allow post-processors to modify the merged bean definition.
		synchronized (mbd.postProcessingLock) {
			if (!mbd.postProcessed) {
				try {
					/**
					 *【2】 收集有注解的属性、方法。
					 *
					 * 1 AutowiredAnnotationBeanPostProcessor 扫描 @Autowired、@Value注解
					 * 2 CommonAnnotationBeanPostProcessor 扫描 @PostConstruct、@Resource、@preDestroy
					 */
					applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
				}
				catch (Throwable ex) {
					throw new BeanCreationException(mbd.getResourceDescription(), beanName,
							"Post-processing of merged bean definition failed", ex);
				}
				mbd.postProcessed = true;
			}
		}

		// Eagerly cache singletons to be able to resolve circular references
		// even when triggered by lifecycle interfaces like BeanFactoryAware.

		/**
		 * bean是单例的、允许循环依赖、当前bean正在创建
		 */
		boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
				isSingletonCurrentlyInCreation(beanName));
		if (earlySingletonExposure) {
			if (logger.isTraceEnabled()) {
				logger.trace("Eagerly caching bean '" + beanName +
						"' to allow for resolving potential circular references");
			}
			/**
			 * 【3】 添加三级缓存,解决循环依赖
			 */
			addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
		}

		// Initialize the bean instance.
		Object exposedObject = bean;
		try {

			/**
			 * 【4】 依赖注入
			 */
			populateBean(beanName, mbd, instanceWrapper);

			/**
			 * 【5】 初始化bean
			 */
			exposedObject = initializeBean(beanName, exposedObject, mbd);
		}
		catch (Throwable ex) {
			if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {
				throw (BeanCreationException) ex;
			}
			else {
				throw new BeanCreationException(
						mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);
			}
		}

		if (earlySingletonExposure) {
			Object earlySingletonReference = getSingleton(beanName, false);
			if (earlySingletonReference != null) {
				if (exposedObject == bean) {
					exposedObject = earlySingletonReference;
				}
				else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
					String[] dependentBeans = getDependentBeans(beanName);
					Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length);
					for (String dependentBean : dependentBeans) {
						if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
							actualDependentBeans.add(dependentBean);
						}
					}
					if (!actualDependentBeans.isEmpty()) {
						throw new BeanCurrentlyInCreationException(beanName,
								"Bean with name '" + beanName + "' has been injected into other beans [" +
								StringUtils.collectionToCommaDelimitedString(actualDependentBeans) +
								"] in its raw version as part of a circular reference, but has eventually been " +
								"wrapped. This means that said other beans do not use the final version of the " +
								"bean. This is often the result of over-eager type matching - consider using " +
								"'getBeanNamesForType' with the 'allowEagerInit' flag turned off, for example.");
					}
				}
			}
		}

		// Register bean as disposable.
		try {
			registerDisposableBeanIfNecessary(beanName, bean, mbd);
		}
		catch (BeanDefinitionValidationException ex) {
			throw new BeanCreationException(
					mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
		}

		return exposedObject;
	}

在这里插入图片描述

2.3 二级缓存

描述: 解决循环依赖,提高获取效率,从三级缓存中获取对象,存入二级缓存,并且删除三级缓存里面的对象。AbstractBeanFactory doGetBean
在这里插入图片描述
DefaultSingletonBeanRegistry getSingleton 方法:

@Nullable
	protected Object getSingleton(String beanName, boolean allowEarlyReference) {
		//一级缓存中获取
		Object singletonObject = this.singletonObjects.get(beanName);
		//如果bean正在创建,还没创建完成
		if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
			synchronized (this.singletonObjects) {
				//从二级缓存中获取
				singletonObject = this.earlySingletonObjects.get(beanName);
				//二级缓存没有
				if (singletonObject == null && allowEarlyReference) {
					//从三级缓存中获取
					ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
					//获取到
					if (singletonFactory != null) {
						//从工厂中拿到对象
						singletonObject = singletonFactory.getObject();
						//升级到二级缓存
						this.earlySingletonObjects.put(beanName, singletonObject);
						//删除三级缓存
						this.singletonFactories.remove(beanName);
					}
				}
			}
		}
		return singletonObject;
	}

3 源码解析

3.1 过程概述

1 StudentService 完成创建、收集注解、存入三级缓存、依赖注入时,需要调用getBean("teacherService")
2 创建TeacherService 完成创建、收集注解、存入三级缓存、依赖注入时,会调用getBean("studentService")
3 AbstractBeanFactory 调用 doGetBean时:
  (1) 调用方法Object sharedInstance = getSingleton(beanName);
  (2) 会从三级缓存中获取获取studentService,存入二级缓存,并且删除三级缓存中studentService。
  (3) 调用getObjectForBeanInstance(sharedInstance, name, beanName, null)方法获取bean,并且把bean返回给teacherService,完成teacherServcie的依赖注入。
  (4) teacherSercice 执行initializeBean(beanName, exposedObject, mbd);
  (5) 当teacherSercice 完成创建后,会加入单例池中,并且删除二级缓存、三级缓存信息。
  (6) studentService完成依赖注入、初始化、存入一级缓存,删除二级缓存,三级缓存信息。

3.2 Debug

描述: studentService 完成实例化、注解收集、存入三级缓存池
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
描述: 依赖注入时会调用 getBean(“teacherService”)
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
描述: 直接在这里打打断点,由于循环依赖,当调用getBean(“teacherService”)时,teacherService会完成创建实例、收集注解、加入三级缓存,在进行依赖注入时,会调用getBean(“studentService”)
在这里插入图片描述
描述: 当执行getBean(“studentService”)会从三级缓存中获取到bean,并且把升级到二级缓存,删除三级缓存信息。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
描述: 这样teacherService能获取到studentService,完成依赖注入,初始化。
在这里插入图片描述
在这里插入图片描述
描述: 获取到创建完成teacherService后,添加到单例池,并且删除二级、三级缓存池信息。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由半码博客整理,本文链接:https://www.bmabk.com/index.php/post/15093.html

(0)

相关推荐

半码博客——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!