spring循环依赖

2年前 (2022) 程序员胖胖胖虎阿
193 0 0

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启动成功");
    }

spring循环依赖

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

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

 spring循环依赖

    单例实例化流程图: spring循环依赖

构造器的循环依赖:  

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;
    }
}

spring循环依赖

报错: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));
		}

spring循环依赖

spring循环依赖

总结:在放入缓存前调用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中存放,在第二次调用以下方法时抛出异常

spring循环依赖

spring循环依赖

版权声明:程序员胖胖胖虎阿 发表于 2022年9月13日 上午8:32。
转载请注明:spring循环依赖 | 胖虎的工具箱-编程导航

相关文章

暂无评论

暂无评论...