spring循环依赖

spring循环依赖主要有三种:

        单例引用类型循环依赖(属性):允许

        构造器的循环依赖:不允许

        多例循环依赖:不允许

单例引用类型循环依赖(属性)

package com.spring.bean;

import lombok.Data;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Data
@Component
public class CirculeA {
    @Autowired
    private CirculeB circuleB;//引用CirculeB

}
package com.spring.bean;

import lombok.Data;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Data
@Component
public class CirculeB {

    @Autowired
    private CirculeA circuleA;//引用CirculeA 

 @org.junit.Test
    public void test3(){
        ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
        System.out.println("spring启动成功");
    }

总结:在circuleA实例化过程中触发circuleB的getBean(),此时circileA的实例已放入到三级缓存中,在circuleB的实例化过程中会触发circuleA的genBean(),直接从缓存中拿到circileA的实例,这样会优先将circuleB是实例化完成,并在circuleA触发circuleB的getBean()时返回,然后继续完成circuleA的实例化;

circuleA第一次实例化会走以下代码,第二次直接从缓存中获取不会走以下代码

 

    单例实例化流程图: 

构造器的循环依赖:  

package com.spring.bean;

import lombok.Data;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

@Data
@Component
public class CirculeB {

    private CirculeA circuleA;

    public CirculeB(CirculeA circuleA) {
        this.circuleA = circuleA;
    }
}
package com.spring.bean;

import lombok.Data;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

@Data
@Component
public class CirculeA {

    private CirculeB circuleB;

    public CirculeA(CirculeB circuleB) {
        this.circuleB = circuleB;
    }
}

报错:org.springframework.beans.factory.UnsatisfiedDependencyException: 
Error creating bean with name 'circuleA' defined in file [D:\XXX\5.2.8\spring_demo\spring_test\target\classes\com\spring\bean\CirculeA.class]: 
Unsatisfied dependency expressed through constructor parameter 0; 
nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: 
Error creating bean with name 'circuleB' defined in file [D:\xxxx\5.2.8\spring_demo\spring_test\target\classes\com\spring\bean\CirculeB.class]:
 Unsatisfied dependency expressed through constructor parameter 0; 
 nested exception is org.springframework.beans.factory.BeanCurrentlyInCreationException: 
 Error creating bean with name 'circuleA': Requested bean is currently in creation: Is there an unresolvable circular reference?

        //创建实例,在这个方法中触发circuleB的getBean()
		if (instanceWrapper == null) {
			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 {
					//AutowiredAnnotationBeanPostProcessor 收集有@Autowire和@Value注解的方法和属性,
					// 放入到injectionMetadataCache缓存中,包装为InjectionMetadata.InjectedElement对象,其中有member,isFiled属性相对重要
					//CommonAnnotationBeanPostProcessor 收集有@PostConstruct和@PreDestroy注解的方法 放入到lifecycleMetadataCache,
					// 有@Resource注解的方法和属性 放入到injectionMetadataCache缓存中,
					// 包装为InjectionMetadata.InjectedElement对象,其中有member,isFiled属性相对重要
					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.
		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));
		}

总结:在放入缓存前调用getBean(),导致缓存中没有,所以每次调用getbean()都会走beforeSingletonCreation()方法,在第二次调用时判断以下条件时(!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.add(beanName))返回true,会抛出异常

多例循环依赖:

package com.spring.bean;

import lombok.Data;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

@Data
@Component
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public class CirculeB {

    @Autowired
    private CirculeA circuleA;
}
package com.spring.bean;

import lombok.Data;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

@Data
@Component
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public class CirculeA {
    @Autowired
    private CirculeB circuleB;

}
 @org.junit.Test
    public void test4(){
        ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
        CirculeA bean = context.getBean(CirculeA.class);
        CirculeB bean1 = context.getBean(CirculeB.class);
        System.out.println("spring启动成功");
    }

会报错:org.springframework.beans.factory.UnsatisfiedDependencyException:
 Error creating bean with name 'circuleA': Unsatisfied dependency expressed through field 'circuleB'; 
 nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: 
 Error creating bean with name 'circuleB': Unsatisfied dependency expressed through field 'circuleA'; 
 nested exception is org.springframework.beans.factory.BeanCurrentlyInCreationException: 
 Error creating bean with name 'circuleA': Requested bean is currently in creation: Is there an unresolvable circular reference?

原因:第一次调用会在ThreadLocal中存放,在第二次调用以下方法时抛出异常

  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Spring循环依赖指的是在Spring中,多个Bean之间存在相互依赖的情况。具体来说,当一个Bean A依赖于另一个Bean B,同时Bean B也依赖于Bean A时,就形成了循环依赖。这种情况下,Spring需要解决Bean的创建和依赖注入的顺序问题。 在Spring中,循环依赖问题是由于Bean的生命周期所引起的。Spring的Bean生命周期包括了Bean的实例化、属性注入、初始化以及销毁等过程。当出现循环依赖时,Spring会通过使用“提前暴露”的方式来解决这个问题。 具体来说,当Spring创建Bean A时,发现它依赖于Bean B,于是会创建一个A的半成品对象,并将其暂时放入一个缓存中。然后,Spring会继续创建Bean B,并将其注入到A的属性中。接着,Spring会继续完成B的创建,并将其放入缓存中。最后,Spring会将A的半成品对象交给B进行依赖注入,完成A的创建,并将其从缓存中移除。 需要注意的是,Spring循环依赖有一定的限制条件。例如,如果Bean A和Bean B都是单例模式,那么它们之间的循环依赖是无法解决的。因为单例模式下,Bean的创建和依赖注入是同时进行的,无法通过缓存来解决循环依赖。在这种情况下,程序员需要手动调整Bean的依赖关系或使用其他解决方案来避免循环依赖的问题。 综上所述,Spring循环依赖是指在Spring中多个Bean之间存在相互依赖的情况。Spring通过使用缓存和提前暴露的方式来解决循环依赖问题,但在某些情况下有一定的限制条件需要注意。<span class="em">1</span><span class="em">2</span><span class="em">3</span><span class="em">4</span>

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值