spring实例化bean之循环依赖

这篇具有很好参考价值的文章主要介绍了spring实例化bean之循环依赖。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

serviceA里注入了serviceB,serviceB里又注入了serviceA,这样在实例化serviceA时,在doCreateBean时的populateBean时会先实例化serviceB,然后实例化serviceB,在serviceB的doCreateBean方法的populateBean又会去找servcieA,这样循环依赖就产生了。
解决办法就是在populateBean之前把当前的serviceA提前暴露,然后在实例化B时可以找到这个提前暴露的serviceA。
关键方法是doCreateBean方法中的addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));

1. DefaultSingletonBeanRegistry#getSingleton

这里就是对当前bean做了一个标志,在实例化前表明当前bean在创建中,在实例化后删除这个标志

	public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
		Assert.notNull(beanName, "Bean name must not be null");
		synchronized (this.singletonObjects) {
			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 + "'");
				}
				//关键1 标志A这个Bean在创建中
				beforeSingletonCreation(beanName);
				boolean newSingleton = false;
				boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
				if (recordSuppressedExceptions) {
					this.suppressedExceptions = new LinkedHashSet<>();
				}
				try {
					//调用createBean方法
					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;
					}
					//关键2 //this.singletonsCurrentlyInCreation.remove(beanName)
					//删除掉Bean A创建中的标识
					afterSingletonCreation(beanName);
				}
				if (newSingleton) {
					addSingleton(beanName, singletonObject);
				}
			}
			return singletonObject;
		}
	}

2. AbstractAutowireCapableBeanFactory#doCreateBean

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

		// Instantiate the bean.
		BeanWrapper instanceWrapper = null;
		if (mbd.isSingleton()) {
			instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
		}
		if (instanceWrapper == null) {
			instanceWrapper = createBeanInstance(beanName, mbd, args);
		}
		final 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 {
					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(1中设置)
		//能满足这个三个条件,则Spring会认为这个此时A是需要提前暴漏的单例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");
			}
			//关键方法
			addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
		}

		// Initialize the bean instance.
		Object exposedObject = bean;
		try {
			populateBean(beanName, mbd, instanceWrapper);
			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 " +
								"'getBeanNamesOfType' 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;
	}

3. DefaultSingletonBeanRegistry#addSingletonFactory

实例化A时,doCreateBean方法populateBean方法执行之前,也就是实例化注入的serviceB之前会调用这个方法。
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));

	protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {
		Assert.notNull(singletonFactory, "Singleton factory must not be null");
		synchronized (this.singletonObjects) {
			if (!this.singletonObjects.containsKey(beanName)) {
				//把当前bean 也就是serviceA关联一个singletonFactory(也就是那个lambda表达式)
				this.singletonFactories.put(beanName, singletonFactory);
				this.earlySingletonObjects.remove(beanName);
				this.registeredSingletons.add(beanName);
			}
		}
	}

给A关联了一个ObjectFactory,也就是getEarlyBeanReference对应的lambda函数对象。放入了singletonFactories中,当B去查BeanA的时候就可以通过getEarlyBeanReference方法获取exposedObject这个早期bean对象。

4.AbstractAutowireCapableBeanFactory#getEarlyBeanReference

这里基本就是把传入的bean返回。命名为exposedObject 早期暴露对象
调用逻辑就是 serviceB实例化时需要注入serviceA,然后在doGetBean的最开始调用getSingleton方法时会获取到serviceA的ObjectFactory,然后执行singletonFactory.getObject()就会执行这个方法拿到bean。

	protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
		Object exposedObject = bean;
		if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
			for (BeanPostProcessor bp : getBeanPostProcessors()) {
				//这个的作用是当前循环依赖的bean恰巧是AOP类型的bean,这里会获取到该bean的代理对象,
				//保证最终实例化的bean和依赖引入的bean是相同的,都是代理类型。
				if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
					SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;
					exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);
				}
			}
		}
		//如果是普通的bean就直接返回了。
		return exposedObject;
	}

查找
比如在实例化serviceA时需要实例化serviceB,实例化serviceB时populateBean方法会再尝试实例化serviceA,doGetBean方法开始会调用getSingleton方法,这个方法里会找到提前暴露的serviceA,保证serviceB可以顺利创建。

	protected Object getSingleton(String beanName, boolean allowEarlyReference) {
		//这里获取不到 因为servcieA的实例化还没完成 也就是servcieA的createBean方法还没执行完,servcieA的getSingleton方法的
		//singletonObject = singletonFactory.getObject()方法也就没执行完,下面的addSingleton方法
		//就不会执行(在这里执行this.singletonObjects.put(beanName, singletonObject)),	
		//singletonObjects中就不会有serviceA。
		Object singletonObject = this.singletonObjects.get(beanName);
		//判断会通过 第二个判断条件是在getSingleton方法的beforeSingletonCreation(beanName)设置的 最开始实例化A时会调用
		if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
			synchronized (this.singletonObjects) {
				//这里也获取不到,因为在最开始servcieA实例化时的addSingletonFactory方法会执行
				//this.earlySingletonObjects.remove(beanName);
				singletonObject = this.earlySingletonObjects.get(beanName);
				//判断会进入
				if (singletonObject == null && allowEarlyReference) {
					//这里能获取到,因为在servcieA实例化时的addSingletonFactory方法会执行
					//this.singletonFactories.put(beanName, singletonFactory);
					ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
					if (singletonFactory != null) {
						//执行这个方法会执行那个lambda表达式 () -> getEarlyBeanReference(beanName, mbd, bean)
						//获取到serviceA
						singletonObject = singletonFactory.getObject();
						this.earlySingletonObjects.put(beanName, singletonObject);
						this.singletonFactories.remove(beanName);
					}
				}
			}
		}
		//获取到返回 此时serviceB就可以得到serviceA了,然后继续创建serviceB
		return singletonObject;
	}

总结
实例化过程:
1.finishBeanFactoryInitialization(beanFactory);
2.beanFactory.preInstantiateSingletons();
3.getBean(beanName);
4.doGetBean
spring实例化bean之循环依赖

这里实例化serviceA时找不到,但是在实例化注入的serviceB时又需要实例化serviceB注入的serviceA,这时就可以获取到
serviceA了。

5.
spring实例化bean之循环依赖
这里的getSingleton方法在执行时执行到**singletonObject = singletonFactory.getObject()**时就会执行lambda表达式的createBean方法。
依赖关系的处理是在createBean方法的doCreateBean方法的populateBean方法
6.doCreateBean
spring实例化bean之循环依赖
关键方法

addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));

这个方法在实例化serviceA,populateBean之前,把serviceA及关联的ObjectFactory(lambda表达式)加到了singletonFactories,这样serviceB实例化时需要实例化servcieA,在doGetBean一开始的getSingleton方法会获取到serviceA,这样就能保证serviceB能创建完成,然后再创建serviceA。

spring实例化bean之循环依赖
springboot2.6之后默认禁用循环依赖。
spring实例化bean之循环依赖
spring实例化bean之循环依赖
开启的话需要增加配置:
spring.main.allow-circular-references=true文章来源地址https://www.toymoban.com/news/detail-474160.html

到了这里,关于spring实例化bean之循环依赖的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • B057-spring增强 依赖注入 AOP 代理模式 创建Bean

    DI:依赖注入 环境准备,即写一个spring测试,见工程 构造器注入 即使用构造器来给Bean的对象的属性赋值 MyBean OtherBean SpringTest-Context.xml SpringTest setter方法注入 即用setter方法给bean对象的属性赋值 MyBean OtherBean SpringTest-Context.xml SpringTest AOP 概念 事务管理:比如可以抽取try catch的

    2024年02月12日
    浏览(48)
  • spring(1):基于XML获取Bean对象以及各种依赖注入方式

    1.1 根据id获取 1.2 根据类型获取 1.3 根据id和类型获取 注意: 当根据类型获取bean时,要求IOC容器中指定类型的bean有且只能有一个。 例如以下XML文件,当IOC容器中一共配置了两个,根据类型获取时会抛出异常。 根据类型来获取bean时,在满足bean唯一性的前提下,其实只是看:

    2024年01月25日
    浏览(44)
  • 【Spring专题】Spring之Bean的生命周期源码解析——阶段二(二)(IOC之属性填充/依赖注入)

    由于Spring源码分析是一个前后联系比较强的过程,而且这边分析,也是按照代码顺序讲解的,所以不了解前置知识的情况下,大概率没办法看懂当前的内容。所以,特别推荐看看我前面的文章(自上而下次序): Spring底层核心原理解析【学习难度: ★★☆☆☆ 】 手写简易

    2024年02月12日
    浏览(39)
  • spring工程的启动流程?bean的生命周期?提供哪些扩展点?管理事务?解决循环依赖问题的?事务传播行为有哪些?

    Spring工程的启动流程主要包括以下几个步骤: 加载配置文件:Spring会读取配置文件(如XML配置文件或注解配置)来获取应用程序的配置信息。 实例化并初始化IoC容器:Spring会创建并初始化IoC容器,即ApplicationContext。在这一步,Spring会解析配置文件,并将配置的Bean实例化。

    2024年02月12日
    浏览(36)
  • 【Spring循环依赖的解决】The dependencies of some of the beans in the application context form a cycle

    启动报错: The dependencies of some of the beans in the application context form a cycle: 两个类相互引用对方,导致Spring在初始化bean的时候不知道先初始化哪个,从而形成循环依赖注入。 类A依赖类B,类B也依赖类A,这种情况就会出现循环依赖。 Bean A → Bean B → Bean A 上面是比较容易发现的

    2024年02月08日
    浏览(45)
  • 【Spring循环依赖报错】The dependencies of some of the beans in the application context form a cycle

           类A需要通过构造函数注入的类B的实例(或者B中声明的Bean),而类B需要通过构造函数注入的类A的实例(或者A中声明的Bean),导致循环依赖注入。 其中一个不要引用对方,避免循环依赖,代码解耦肯定是最优解。 选择其中一个使用@Lazy 注解。        延迟互相

    2024年02月07日
    浏览(47)
  • Springboot依赖注入Bean的三种方式,final+构造器注入Bean

    @Autowired注解的一大使用场景就是Field Injection。 通过Java的反射机制实现,所以private的成员也可以被注入具体的对象 优点 代码少,简洁明了。 新增依赖十分方便,不需要修改原有代码 缺点 容易出现空指针异常。Field 注入允许构建对象实例时依赖的对象为空,导致空指针异常

    2024年02月02日
    浏览(46)
  • quarkus依赖注入之三:用注解选择注入bean

    这里分类和汇总了欣宸的全部原创(含配套源码):https://github.com/zq2599/blog_demos 本文是《quarkus依赖注入》系列的第三篇,前文咱们掌握了创建bean的几种方式,本篇趁热打铁,学习一个与创建bean有关的重要知识点:一个接口如果有多个实现类时,bean实例应该如何选择其中的一个

    2024年02月14日
    浏览(44)
  • quarkus依赖注入之一:创建bean

    这里分类和汇总了欣宸的全部原创(含配套源码):https://github.com/zq2599/blog_demos 对一名java程序员来说,依赖注入应该是个熟悉的概念,简单的说就是:我要用XXX,但我不负责XXX的生产 以下代码来自spring官方,serve方法要使用MyComponent类的doWork方法,但是不负责MyComponent对象的实

    2024年02月15日
    浏览(39)
  • quarkus依赖注入之四:选择注入bean的高级手段

    这里分类和汇总了欣宸的全部原创(含配套源码):https://github.com/zq2599/blog_demos 本文是《quarkus依赖注入》系列的第四篇,在应用中,一个接口有多个实现是很常见的,那么依赖注入时,如果类型是接口,如何准确选择实现呢?前文介绍了五种注解,用于通过配置项、profile等手

    2024年02月14日
    浏览(39)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包