java lazy实现依赖调用_Spring循环依赖解决(五)

spring可以解决属性注入循环依赖,默认不能解决构造器注入循环依赖。

spring创建对象分两步,①初始化实例对象,②初始化对象属性。

spring循环依赖,最初引用的就是半成品,也就是只初始化示例对象,还没有初始化对象属性。

1.  循环依赖导致系统启动失败的情况

发生循环依赖一般是在构造方法中注入引起循环依赖错误。

1. 循环依赖

一般发生循环依赖也就是构造方法发生依赖,比如:

类A:

packageqz;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.stereotype.Component;

@Componentpublic classCircularDependencyA {privateCircularDependencyB circB;

@AutowiredpublicCircularDependencyA(CircularDependencyB circB) {this.circB =circB;

}

}

类B:

packageqz;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.stereotype.Component;

@Componentpublic classCircularDependencyB {privateCircularDependencyA circA;

@AutowiredpublicCircularDependencyB(CircularDependencyA circA) {this.circA =circA;

}

}

主类:

packageqz;importorg.springframework.context.annotation.AnnotationConfigApplicationContext;importorg.springframework.context.annotation.ComponentScan;importjava.io.IOException;

@ComponentScan("qz")public classMainApp {public static void main(String[] args) throwsInterruptedException, IOException {

AnnotationConfigApplicationContext applicationContext= new AnnotationConfigApplicationContext(MainApp.class);

applicationContext.close();

}

}

结果:

Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'circularDependencyB' defined in file [E:\xiangmu\springsource2\spring-framework-5.1.x\mytest\build\classes\java\main\qz\CircularDependencyB.class]: Unsatisfied dependency expressed through constructor parameter 0; nested exception is org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'circularDependencyA': Requested bean is currently in creation: Is there an unresolvable circular reference?

2. 解决办法

1.  重新设计,说白了就是构造注入改为属性注入

类A:

packageqz;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.stereotype.Component;

@Componentpublic classCircularDependencyA {

@AutowiredprivateCircularDependencyB circB;

}

类B:

packageqz;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.stereotype.Component;

@Componentpublic classCircularDependencyB {

@AutowiredprivateCircularDependencyA circA;

}

2. 使用@Lazy 注解: 只用一方打注解即可

packageqz;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.context.annotation.Lazy;importorg.springframework.stereotype.Component;

@Componentpublic classCircularDependencyA {privateCircularDependencyB circB;

@AutowiredpublicCircularDependencyA(@Lazy CircularDependencyB circB) {this.circB =circB;

}

}

3.  使用@PostConstruct

类A

packageqz;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.stereotype.Component;importjavax.annotation.PostConstruct;

@Componentpublic classCircularDependencyA {

@AutowiredprivateCircularDependencyB circB;

@PostConstructpublic voidinit() {

circB.setCircA(this);

}publicCircularDependencyB getCircB() {returncircB;

}

}

类B:

packageqz;importorg.springframework.stereotype.Component;

@Componentpublic classCircularDependencyB {privateCircularDependencyA circA;public voidsetCircA(CircularDependencyA circA) {this.circA =circA;

}

}

4. 实现ApplicationContextAware and InitializingBean 接口

类A:

packageqz;importorg.springframework.beans.BeansException;importorg.springframework.beans.factory.InitializingBean;importorg.springframework.context.ApplicationContext;importorg.springframework.context.ApplicationContextAware;importorg.springframework.stereotype.Component;

@Componentpublic class CircularDependencyA implementsApplicationContextAware, InitializingBean {privateCircularDependencyB circB;privateApplicationContext context;publicCircularDependencyB getCircB() {returncircB;

}

@Overridepublic void afterPropertiesSet() throwsException {

circB= context.getBean(CircularDependencyB.class);

}

@Overridepublic void setApplicationContext(final ApplicationContext ctx) throwsBeansException {

context=ctx;

}

}

类B:

packageqz;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.stereotype.Component;

@Componentpublic classCircularDependencyB {privateCircularDependencyA circA;

@Autowiredpublic voidsetCircA(CircularDependencyA circA) {this.circA =circA;

}

}

2. 属性注入循环依赖Spring解决方式分析

通过之前分析得到,Spring创建Bean是从getBean开始。主要分为两部分。当前对象实例化和对象属性的实例化。对象的实例化通过反射实现,对象的属性是在实例化之后通过注入或者其他方式实现的。

org.springframework.beans.factory.support.AbstractBeanFactory#doGetBean 源码如下:

protected T doGetBean(

String name, @Nullable Class requiredType, @Nullable Object[] args, booleantypeCheckOnly)throwsBeansException {

String beanName=transformedBeanName(name);

Object bean;

Object sharedInstance=getSingleton(beanName);if (sharedInstance != null && args == null) {if(logger.isTraceEnabled()) {if(isSingletonCurrentlyInCreation(beanName)) {

logger.trace("Returning eagerly cached instance of singleton bean '" + beanName +

"' that is not fully initialized yet - a consequence of a circular reference");

}else{

logger.trace("Returning cached instance of singleton bean '" + beanName + "'");

}

}

bean= getObjectForBeanInstance(sharedInstance, name, beanName, null);

}else{//Fail if we're already creating this bean instance://We're assumably within a circular reference.

if(isPrototypeCurrentlyInCreation(beanName)) {throw newBeanCurrentlyInCreationException(beanName);

}//Check if bean definition exists in this factory.

BeanFactory parentBeanFactory =getParentBeanFactory();if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {//Not found -> check parent.

String nameToLookup =originalBeanName(name);if (parentBeanFactory instanceofAbstractBeanFactory) {return((AbstractBeanFactory) parentBeanFactory).doGetBean(

nameToLookup, requiredType, args, typeCheckOnly);

}else if (args != null) {//Delegation to parent with explicit args.

return(T) parentBeanFactory.getBean(nameToLookup, args);

}else if (requiredType != null) {//No args -> delegate to standard getBean method.

returnparentBeanFactory.getBean(nameToLookup, requiredType);

}else{return(T) parentBeanFactory.getBean(nameToLookup);

}

}if (!typeCheckOnly) {

markBeanAsCreated(beanName);

}try{

RootBeanDefinition mbd=getMergedLocalBeanDefinition(beanName);

checkMergedBeanDefinition(mbd, beanName, args);//Guarantee initialization of beans that the current bean depends on.

String[] dependsOn =mbd.getDependsOn();if (dependsOn != null) {for(String dep : dependsOn) {if(isDependent(beanName, dep)) {throw newBeanCreationException(mbd.getResourceDescription(), beanName,"Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");

}

registerDependentBean(dep, beanName);try{

getBean(dep);

}catch(NoSuchBeanDefinitionException ex) {throw newBeanCreationException(mbd.getResourceDescription(), beanName,"'" + beanName + "' depends on missing bean '" + dep + "'", ex);

}

}

}//Create bean instance.

if(mbd.isSingleton()) {

sharedInstance= getSingleton(beanName, () ->{try{returncreateBean(beanName, mbd, args);

}catch(BeansException ex) {//Explicitly remove instance from singleton cache: It might have been put there//eagerly by the creation process, to allow for circular reference resolution.//Also remove any beans that received a temporary reference to the bean.

destroySingleton(beanName);throwex;

}

});

bean=getObjectForBeanInstance(sharedInstance, name, beanName, mbd);

}else if(mbd.isPrototype()) {//It's a prototype -> create a new instance.

Object prototypeInstance = null;try{

beforePrototypeCreation(beanName);

prototypeInstance=createBean(beanName, mbd, args);

}finally{

afterPrototypeCreation(beanName);

}//create bean

bean =getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);

}else{

String scopeName=mbd.getScope();if (!StringUtils.hasLength(scopeName)) {throw new IllegalStateException("No scope name defined for bean ´" + beanName + "'");

}

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, () ->{

beforePrototypeCreation(beanName);try{returncreateBean(beanName, mbd, args);

}finally{

afterPrototypeCreation(beanName);

}

});

bean=getObjectForBeanInstance(scopedInstance, name, beanName, mbd);

}catch(IllegalStateException ex) {throw newBeanCreationException(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);throwex;

}

}//Check if required type matches the type of the actual bean instance.

if (requiredType != null && !requiredType.isInstance(bean)) {try{

T convertedBean=getTypeConverter().convertIfNecessary(bean, requiredType);if (convertedBean == null) {throw newBeanNotOfRequiredTypeException(name, requiredType, bean.getClass());

}returnconvertedBean;

}catch(TypeMismatchException ex) {if(logger.isTraceEnabled()) {

logger.trace("Failed to convert bean '" + name + "' to required type '" +ClassUtils.getQualifiedName(requiredType)+ "'", ex);

}throw newBeanNotOfRequiredTypeException(name, requiredType, bean.getClass());

}

}return(T) bean;

}

解释:

1. Object sharedInstance = getSingleton(beanName); 先尝试获取对象实例,查看getSingleton(beanName) 源码如下:org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#getSingleton(java.lang.String, boolean)

/*** Return the (raw) singleton object registered under the given name.

*

Checks already instantiated singletons and also allows for an early

* reference to a currently created singleton (resolving a circular reference).

*@parambeanName the name of the bean to look for

*@paramallowEarlyReference whether early references should be created or not

*@returnthe registered singleton object, or {@codenull} if none found*/@Nullableprotected Object getSingleton(String beanName, booleanallowEarlyReference) {//Quick check for existing instance without full singleton lock//尝试从一级缓存获取

Object singletonObject = this.singletonObjects.get(beanName);//如果一级不存在,则判断当前对象是否处于创建过程中(第一次尝试获取A对象实例之后就会标记为创建中)。

if (singletonObject == null &&isSingletonCurrentlyInCreation(beanName)) {//从二级缓存中查询,获取Bean的早期引用,实例化完成,但未赋值完成的bean

singletonObject = this.earlySingletonObjects.get(beanName);//二级缓存不存在,并且允许创建早期引用

if (singletonObject == null &&allowEarlyReference) {synchronized (this.singletonObjects) {

singletonObject= this.singletonObjects.get(beanName);if (singletonObject == null) {

singletonObject= this.earlySingletonObjects.get(beanName);if (singletonObject == null) {//从三级缓存中查询,实例化完成,属性为装配完成

ObjectFactory> singletonFactory = this.singletonFactories.get(beanName);if (singletonFactory != null) {//获取目标对象的实例

singletonObject =singletonFactory.getObject();// //添加到二级缓存中

this.earlySingletonObjects.put(beanName, singletonObject);//从三级缓存中移除

this.singletonFactories.remove(beanName);

}

}

}

}

}

}returnsingletonObject;

}

org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#isSingletonCurrentlyInCreation源码如下:

public booleanisSingletonCurrentlyInCreation(String beanName) {return this.singletonsCurrentlyInCreation.contains(beanName);

}

一二三级缓存全部查询,如果三级缓存存在则将Bean早期引用存放在二级缓存中并移除三级缓存。(升级为二级缓存)。这里看到用到了三个map,如下:

/**Cache of singleton objects: bean name to bean instance.*/

private final Map singletonObjects = new ConcurrentHashMap<>(256);/**Cache of singleton factories: bean name to ObjectFactory.*/

private final Map> singletonFactories = new HashMap<>(16);/**Cache of early singleton objects: bean name to bean instance.*/

private final Map earlySingletonObjects = new ConcurrentHashMap<>(16);

singletonObjects 对应一级缓存。 存放完全实例化属性赋值完成的Bean,可以直接使用

earlySingletonObjects  对应二级缓存,存放早起Bean的引用,尚未属性装配的Bean,也就是半成品

singletonFactories  对应三级缓存,存放实例化完成的Bean工厂。

2. 如下代码是创建Bean且加入相关缓存

if(mbd.isSingleton()) {

sharedInstance= getSingleton(beanName, () ->{try{returncreateBean(beanName, mbd, args);

}catch(BeansException ex) {//Explicitly remove instance from singleton cache: It might have been put there//eagerly by the creation process, to allow for circular reference resolution.//Also remove any beans that received a temporary reference to the bean.

destroySingleton(beanName);throwex;

}

});

bean=getObjectForBeanInstance(sharedInstance, name, beanName, mbd);

}

2.1 这段代码实际上用了一个lambda表达式,也就是如果getSingleton 获取不到bean则会创建bean。org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#getSingleton(java.lang.String, org.springframework.beans.factory.ObjectFactory>)源码如下:

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 newBeanCreationNotAllowedException(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 + "'");

}

beforeSingletonCreation(beanName);boolean newSingleton = false;boolean recordSuppressedExceptions = (this.suppressedExceptions == null);if(recordSuppressedExceptions) {this.suppressedExceptions = new LinkedHashSet<>();

}try{

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) {throwex;

}

}catch(BeanCreationException ex) {if(recordSuppressedExceptions) {for (Exception suppressedException : this.suppressedExceptions) {

ex.addRelatedCause(suppressedException);

}

}throwex;

}finally{if(recordSuppressedExceptions) {this.suppressedExceptions = null;

}

afterSingletonCreation(beanName);

}if(newSingleton) {

addSingleton(beanName, singletonObject);

}

}returnsingletonObject;

}

}

beforeSingletonCreation(beanName); 方法会将创建标记存入Map中,标记着该Bean开始创建。org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#beforeSingletonCreation源码如下:

protected voidbeforeSingletonCreation(String beanName) {if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.add(beanName)) {throw newBeanCurrentlyInCreationException(beanName);

}

}

2.2 也就是获取不到Bean调用org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#createBean方法,方法中委托给org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#doCreateBean

protectedObject doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)throwsBeanCreationException {//Instantiate the bean.

BeanWrapper instanceWrapper = null;if(mbd.isSingleton()) {

instanceWrapper= this.factoryBeanInstanceCache.remove(beanName);

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

applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);

}catch(Throwable ex) {throw newBeanCreationException(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));

}//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 newBeanCreationException(

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 actualDependentBeans = new LinkedHashSet<>(dependentBeans.length);for(String dependentBean : dependentBeans) {if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {

actualDependentBeans.add(dependentBean);

}

}if (!actualDependentBeans.isEmpty()) {throw newBeanCurrentlyInCreationException(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 newBeanCreationException(

mbd.getResourceDescription(), beanName,"Invalid destruction signature", ex);

}returnexposedObject;

}

2.3 可以看到 addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean)) 代码调用添加三级缓存。org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#addSingletonFactory如下:

/*** Add the given singleton factory for building the specified singleton

* if necessary.

*

To be called for eager registration of singletons, e.g. to be able to

* resolve circular references.

*@parambeanName the name of the bean

*@paramsingletonFactory the factory for the singleton object*/

protected void addSingletonFactory(String beanName, ObjectFactory>singletonFactory) {

Assert.notNull(singletonFactory,"Singleton factory must not be null");synchronized (this.singletonObjects) {//一级缓存不存在

if (!this.singletonObjects.containsKey(beanName)) {//放入三级缓存

this.singletonFactories.put(beanName, singletonFactory);//从二级缓存移除

this.earlySingletonObjects.remove(beanName);this.registeredSingletons.add(beanName);

}

}

}

2.4 上面2.2中的 populateBean 方法调用会进行依赖注入等操作,如果属性注入其他bean会循环调用getBean方法

2.5 在2.1的代码块中可以看到addSingleton(beanName, singletonObject);  加入缓存的代码。org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#addSingleton:

/*** Add the given singleton object to the singleton cache of this factory.

*

To be called for eager registration of singletons.

*@parambeanName the name of the bean

*@paramsingletonObject the singleton object*/

protected voidaddSingleton(String beanName, Object singletonObject) {synchronized (this.singletonObjects) {//一级添加

this.singletonObjects.put(beanName, singletonObject);//二级移除

this.singletonFactories.remove(beanName);//三级移除

this.earlySingletonObjects.remove(beanName);this.registeredSingletons.add(beanName);

}

}

加入缓存之后完成整个bean的创建以及赋值。

也就是二级缓存相当于个过渡。从三级到一级的过渡,放的是一个半成品。

总结下流程相当于:假设A依赖B、B依赖A。

(1)A依次执行doGetBean、查询缓存、createBean创建实例,实例化完成放入三级缓存singletonFactories中,接着执行populateBean方法装配属性,但是发现有一个属性是B的对象。

(2)再次调用doGetBean方法创建B的实例,依次执行doGetBean、查询缓存、createBean创建实例,实例化完成之后放入三级缓存singletonFactories中,执行populateBean装配属性,但是此时发现有一个属性是A对象。

(3)因此再次调用doGetBean创建A的实例,但是执行到getSingleton查询缓存的时候,从三级缓存中查询到了A的实例(早期引用,未完成属性装配),此时移到二级缓存中然后返回,不用执行后续的流程创建A了,那么B就完成了属性装配,此时是一个完整的对象放入到一级缓存singletonObjects中。

(4)B创建完成了,则A自然完成了属性装配,也创建完成放入了一级缓存singletonObjects中。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值