什么是循环依赖
说白了就是对象之间的依赖关系成环
例如A->B,B->C,C->A,并不限于对象的多少,最终成环就是循环依赖,也因此循环依赖的发生可能是十分复杂的。,如果使用属性注入的话,开发过程中甚至很难察觉。
为什么要避免循环依赖
循环依赖会为系统带来很多意想不到的问题,下面我们来简单讨论一下
一、循环依赖会产生多米诺骨牌效应
换句话说就是牵一发而动全身,想象一下平静的湖面落入一颗石子,涟漪会瞬间向周围扩散。
循环依赖形成了一个环状依赖关系, 这个环中的某一点产生不稳定变化,都会导致整个环产生不稳定变化
实际的体验就是
- 难以为代码编写测试,因为易变导致写的测试也不稳定
- 难以重构,因为互相依赖,你改动一个自然会影响其他依赖对象
- 难以维护,你根本不敢想象你的改动会造成什么样的后果
- …
spring希望我们的依赖关系是单向的,这样的方式在一定程度保证了逻辑的清晰利于维护,也利于扩展
二、一个例子 A,B两个bean相互依赖,那么必然A和B存在其中一种状态,一个bean未完成初始化就被注入到对方属性字段可以被使用,那么可能在 A还没有完成初始化的时候,B就引用并调用了A进行某些操作,可能出现一些意料之外的情况
三、循环依赖会导致内存溢出
一个简单的例子
class A{
public void a(){b.b()
}
}class B{
public void b(){a.a()
}
}
属性注入
通过@Component创建的注入到工厂
通常使用@Autowired或者@Resource注解在属性字段上
@Resource
@Resource是Java自己的注解
@Resource有两个属性是比较重要的,分别是name和type;Spring将@Resource注解的name属性解析为bean的名字,而type属性则解析为bean的类型。所以如果使用name属性,则使用byName的自动注入策略,而使用type属性时则使用byType自动注入策略。默认按name进行注入。
如果某个类型有多个,可以通过那么指定
@Autowired
@AutoWired是spring的注解,Autowired只根据type进行注入,不会去匹配name。如果涉及到type无法辨别注入对象时,那需要依赖@Qualifier或@Primary注解一起来修饰。@Resource默认按名称方式进行bean匹配,但是Autowired额外支持require属性,是否要求一定注入
@Autowired默认按类型方式进行bean匹配。
使用@AutoWired变量注解方式时,会有黄色波浪线,idea会提示:
Spring团队建议:“在bean中始终使用基于构造函数的依赖注入。始终对强制依赖项使用断言”。
意思是说,用@Autowired的注入时,尽量用基于构造函数的依赖注入,而不是变量的方式注入。
这就是构造函数方式的依赖注入:
那么为什么不推荐属性注入?
1、可能会造成NPE,如下:
public class TestController {@Autowiredprivate TestService testService;private String name;public TestController(){this.name= testService.getName();}}
这段代码执行时会报NPE。Java类会先执行构造函数,然后在通过@Autowired注入实例,二构造函数里面需要注入的对象,因此在执行构造函数的时候就会报错。
2、还可能回导致循环依赖,即A里面注入B,B里面又注入A。(构造注入会启动时就会报错及时发现)
注:在代码中发现构造方法中注入了很多依赖,显得很臃肿,对于这个问题,说明类中有太多的责任,违反了类的单一性职责原则,这时候需要考虑使用单一职责原则进行代码重构。
属性注入对循环依赖的处理
首先说明属性注入对于循环依赖是容忍的,正常情况下出现循环依赖并不会报错,程序正常启动运行
bean工厂的三级缓存
默认bean工厂实现为DefaultListableBeanFactory
其有一个父类为DefaultSingletonBeanRegistry
其中有大名鼎鼎的三级缓存
/*存放已经完成创建的bean */private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);/** 存放存放生成bean的工厂,生成bean后先放入earlySingletonObjects */private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);/*存放提前暴露的bean实例,还未完全初始化*/private final Map<String, Object> earlySingletonObjects = new ConcurrentHashMap<>(16);
那么这这三个缓存的作用分别是什么.先看bean注册到bean工厂的过程。
一个bean的注入流程
从创建一个bean开始
org.springframework.beans.factory.support.AbstractBeanFactory#doGetBean
在创建bean的方法中
if (mbd.isSingleton()) {sharedInstance = getSingleton(beanName, () -> {try {return createBean(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);throw ex;}});bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);}
进入
org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#getSingleton(java.lang.String, org.springframework.beans.factory.ObjectFactory<?>)
首先从singletonObjects中获取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 + "'");}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) {throw ex;}}
那么如果获取不到,先判断singletonsCurrentlyInDestruction,变量名看事如果这个变量正在被销毁,那么抛出异常,继续来到beforeSingletonCreation方法
/*** Callback before singleton creation.* <p>The default implementation register the singleton as currently in creation.* @param beanName the name of the singleton about to be created* @see #isSingletonCurrentlyInCreation*/protected void beforeSingletonCreation(String beanName) {if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.add(beanName)) {throw new BeanCurrentlyInCreationException(beanName);}}
会将beanName放入到singletonsCurrentlyInCreation中,代表这个bean正在创建中
private final Set<String> singletonsCurrentlyInCreation =Collections.newSetFromMap(new ConcurrentHashMap<>(16));
这是一个set集合,如果已经在创建,那么会抛出BeanCurrentlyInCreationException
然后继续
try {singletonObject = singletonFactory.getObject();newSingleton = true;}
开始创建bean
进入关键方法org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#doCreateBean
// Instantiate the bean.BeanWrapper instanceWrapper = null;if (instanceWrapper == null) {//创建一个bean的实例instanceWrapper = createBeanInstance(beanName, mbd, args);}Object bean = instanceWrapper.getWrappedInstance();
在createBeanInstance中,有多种和实例化方法的方式,通过配置类方法创建,通过构造方法创建。或者就是根据默认的无参构造方法进行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));}
判断earlySingletonExposure 是否提前暴露,是否成立有两个条件
- 判断是否允许循环依赖,如果不允许肯定不会提前暴露
- 另外还需要判断当前bean是不是处在被创建的过程中,根据singletonsCurrentlyInCreation中是否包含进行判断,再开始创建bean之前,就会将beanName先放进来
public boolean isSingletonCurrentlyInCreation(String beanName) {return this.singletonsCurrentlyInCreation.contains(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));}
添加一个回调到SingletonFactory
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);}}}
逻辑是将beanName和回调的ObjectFactory lamda,放入到singletonFactories,并且从earlySingletonObjects中移除,添加到registeredSingletons代表这个bean已经在bean工厂,后续如果通过getBean获取可以获取到。至于怎么获取,后面看
再看getEarlyBeanReference这个方法
其中的逻辑是把bean的引用,经过SmartInstantiationAwareBeanPostProcessor处理,后返回
protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {Object exposedObject = bean;if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {for (BeanPostProcessor bp : getBeanPostProcessors()) {if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);}}}return exposedObject;}
注意这个SmartInstantiationAwareBeanPostProcessor对循环依赖起到重要作用
getEarlyBeanReference
获得提前暴露的bean引用,主要用于解决循环引用的问题。
getEarlyBeanReference:该触发点发生在postProcessAfterInstantiation之后,当有循环依赖的场景,当bean实例化好之后,为了防止有循环依赖,会提前暴露回调方法,用于bean实例化的后置处理。这个方法就是在提前暴露的回调方法中触发。
看下这个方法的实现类
org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#getEarlyBeanReference
@Overridepublic Object getEarlyBeanReference(Object bean, String beanName) {Object cacheKey = getCacheKey(bean.getClass(), beanName);this.earlyProxyReferences.put(cacheKey, bean);return wrapIfNecessary(bean, beanName, cacheKey);}
看的出来,如果获取提前暴露的bean,那么对于需要进行代理的ben,进行必要的代理。
继续向下
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);}}
执行populateBean,这个方法对使用的配置文件,对依赖的bean进行使用getBean获取,并且注入到对应属性。
其实仔细想一下,对某个bean,只要populateBean方法执行完毕,那么这个bean的所有依赖关系都注入完毕,包括循环依赖也被执行完毕。
因此循环依赖的的解决过程从populateBean这个方法开始分析
例如现在假设,当前A依赖了B,B又依赖了A,构成循环
进入populateBean之后,为了注入B会调用getBean(B)
对于B的加载过程于A相同,也会提前暴露,在解析B的依赖时,会去获取调用getBean(A),那么关键来了,因为此时A还没有加载完成,但是已经提前暴露,那么看看这个过程
在org.springframework.beans.factory.support.AbstractBeanFactory#doGetBean中
// Eagerly check singleton cache for manually registered singletons.Object sharedInstance = getSingleton(beanName);
先尝试获取bean
org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#getSingleton(java.lang.String, boolean)
@Nullableprotected Object getSingleton(String beanName, boolean allowEarlyReference) {// Quick check for existing instance without full singleton lockObject singletonObject = this.singletonObjects.get(beanName);if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {singletonObject = this.earlySingletonObjects.get(beanName);if (singletonObject == null && allowEarlyReference) {synchronized (this.singletonObjects) {// Consistent creation of early reference within full singleton locksingletonObject = 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);}}}}}}return singletonObject;}
分别尝试从singletonObjects和earlySingletonObjects中获取实例
如都获取不到锁住singletonObjects再次读一遍,如果没有其他线程修改,通过singletonFactory生成对象,放入
earlySingletonObjects(提前暴露未完全创建完成的bean)并从singletonFactories中移除
从这里就能看出来
singletonObjects,earlySingletonObjects,singletonFactory分别是一二三级缓存
singletonFactory.getObject()会进入getEarlyBeanReference方法
前面已经说过SmartInstantiationAwareBeanPostProcessor会对需要代理类进行处理,对于无需代理的类 ,直接返回未创建完成的bean的引用即可(这里也是循环依赖的一个坏处,比如B完成了bean 的创建后,调用afterPropertiesSet等方法,使用到了A,但是此时的A还没初始化完成,会发生一些意想不到的情况)
代理的特殊情况
对于需要代理的bean进入org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#getEarlyBeanReference
@Overridepublic Object getEarlyBeanReference(Object bean, String beanName) {Object cacheKey = getCacheKey(bean.getClass(), beanName);this.earlyProxyReferences.put(cacheKey, bean);return wrapIfNecessary(bean, beanName, cacheKey);}
会将bean 缓存到到earlyProxyReferences中
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {return bean;}if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {return bean;}if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {this.advisedBeans.put(cacheKey, Boolean.FALSE);return bean;}helloServiceA// Create proxy if we have advice.Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);if (specificInterceptors != DO_NOT_PROXY) {this.advisedBeans.put(cacheKey, Boolean.TRUE);Object proxy = createProxy(bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));this.proxyTypes.put(cacheKey, proxy.getClass());return proxy;}this.advisedBeans.put(cacheKey, Boolean.FALSE);return bean;}
对于需要进行代理的bean 进行代理操作,然后返回需要代理的类
那么也就是说对于需要代理的类,注意是由AnnotationAwareAspectJAutoProxyCreator处理的,
AnnotationAwareAspectJAutoProxyCreator是用来处理aop,transactional切面的一个代理生成类,并不所所有的代理增强都由其实现,AnnotationAwareAspectJAutoProxyCreator实现了SmartInstantiationAwareBeanPostProcessor的getEarlyBeanReference,因此其具备在提前暴露就能够生成代理类的能力(有了解决循环依赖的能力!)
会在getEarlyBeanReference时就 生成代理类,使用代理类进行提前暴露。
如果不需要SmartInstantiationAwareBeanPostProcessor进行特殊处理,那么直接返回原有的bean就好了。
AnnotationAwareAspectJAutoProxyCreator除了在提前暴露的时候会判断生成代理类之外,完成bean的依赖注入后,还需要执行AnnotationAwareAspectJAutoProxyCreator对当前bean进行判断是否需要进行,aop,事务的增强代理。
在populateBean方法执行完毕之后。代表当前bean所依赖的所有bean都已经被注入到当前的bean实例
继续来到
Object exposedObject = bean;
exposedObject = initializeBean(beanName, exposedObject, mbd);
对bean做进一步加工处理,得到真正暴露的bean(getBean方法的结果)。
if (mbd == null || !mbd.isSynthetic()) {wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);}try {invokeInitMethods(beanName, wrappedBean, mbd);}catch (Throwable ex) {throw new BeanCreationException((mbd != null ? mbd.getResourceDescription() : null),beanName, "Invocation of init method failed", ex);}if (mbd == null || !mbd.isSynthetic()) {wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);}
其中会执行,前置,后置的beanPostProcess,和InitialBean的afterPropertiesSet方法。
在
AnnotationAwareAspectJAutoProxyCreator的后置方法中
也会对bean进行代理(并不是所有bean都会提前暴露生成代理,只有循环依赖才会提前暴露)
@Overridepublic Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {if (bean != null) {Object cacheKey = getCacheKey(bean.getClass(), beanName);if (this.earlyProxyReferences.remove(cacheKey) != bean) {return wrapIfNecessary(bean, beanName, cacheKey);}}return bean;}
注意!如果earlyProxyReferences已经存在了这个bean,代表该bean已经被提前暴露生成过了代理,那么不再进行重复代理!
判断是否循环依赖
完成initializeBean方法后,继续
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.");}}}}
如果允许循环依赖,先获取earlySingletonReference,就是提前暴露的那个实例(可能时代理,也肯不是代理)
如果时空,那么确定不存在循环依赖,直接返回就好了。
如果不为空,进一步判断
if (exposedObject == bean) {exposedObject = earlySingletonReference;}
exposedObject是对bean的进一****步加工,如果二者不相等,那么可能带来一个一个严重的问题,那就是提前暴露的是bean。那么别的实例提通过获取bean的提前暴露依赖并注入了的当前bean的,这对于单例模式的bean显然是无法接受的。(这种情况下,会报出循环依赖的错误)
因此spring要求exposedObject和bean要相等,并且相等的情况下要让exposedObject = earlySingletonReference;,因为在候取提前暴露的bean实例时,同样可以更改这个bean。
AnnotationAwareAspectJAutoProxyCreator就是通过在获取提前暴露的bean时生成代理,并且避免initializeBean中代理,这样保证了exposedObject == bean,解决循环依赖的报错。
setter注入属性
@Autowired@Qualifier("helloServiceA")public void setHelloServiceA(HelloService helloServiceA) {this.helloServiceA = helloServiceA;}
这种形式进行依赖注入于Autowire的流程相同,支持bean循环依赖
方法参数注入
@ Bean注解注入循环依赖的产生
例子
@Beanpublic HelloService helloServiceA(@Qualifier("helloServiceB") HelloService helloServiceB){HelloServiceA helloServiceA = new HelloServiceA();helloServiceA.setHelloServiceB(helloServiceB);return helloServiceA;}@Beanpublic HelloService helloServiceB(@Qualifier("helloServiceA") HelloService helloServiceA){HelloServiceB helloServiceB = new HelloServiceB();helloServiceB.setHelloServiceA(helloServiceA);return helloServiceB;}
方法创建的bean是不支持循环依赖的
首先创建helloServiceA,在创建bean实例时,不是使用默认构造创建的,而是通过方法创建实例返回
if (mbd.getFactoryMethodName() != null) {return instantiateUsingFactoryMethod(beanName, mbd, args);}
其中会对方法的每个入参进行解析
for (int paramIndex = 0; paramIndex < paramTypes.length; paramIndex++) {Object autowiredArgument = resolveAutowiredArgument(methodParam, beanName, autowiredBeanNames, converter, fallback);args.rawArguments[paramIndex] = autowiredArgument;args.arguments[paramIndex] = autowiredArgument;args.preparedArguments[paramIndex] = autowiredArgumentMarker;args.resolveNecessary = true;}
对每个参数进行解析注入
看是如何进行解析的
return this.beanFactory.resolveDependency(new DependencyDescriptor(param, true), beanName, autowiredBeanNames, typeConverter);
最终在解析的时候调用getBean方法获取bean实例
public Object resolveCandidate(String beanName, Class<?> requiredType, BeanFactory beanFactory)throws BeansException {return beanFactory.getBean(beanName);}
那么又会对依赖的bean进行获取
被依赖helloServiceB,刚好也依赖helloServiceA
**创建helloServiceB的过程与创建helloServiceA的一致,不在重复·。**同样在解析入参时也会调用
getBean(helloServiceA),进行对helloServiceA的获取
那么看下这个doGetBean方法
//首先尝试从缓存中获取
Object sharedInstance = getSingleton(beanName);
前面看过这个getSingleton(String beanName, boolean allowEarlyReference)这个方法,
protected Object getSingleton(String beanName, boolean allowEarlyReference) {// Quick check for existing instance without full singleton lockObject singletonObject = this.singletonObjects.get(beanName);if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {singletonObject = this.earlySingletonObjects.get(beanName);if (singletonObject == null && allowEarlyReference) {synchronized (this.singletonObjects) {// Consistent creation of early reference within full singleton locksingletonObject = 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);}}}}}}return singletonObject;}
如果singletonObjects中为空的话会尝试,获取提前暴露的实例
但是通过方法创建的bean并没有提前暴露这个步骤。因此这里的值就是空的。
sharedInstance = getSingleton(beanName, () -> {try {return createBean(beanName, mbd, args);}}
发现又使用了getSingleton获取,不过这是一个重载方法。和上面的getSingleton(beanName);有些不同
getSingleton(String beanName, ObjectFactory<?> singletonFactory)
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {Assert.notNull(beanName, "Bean name must not be null");synchronized (this.singletonObjects) {······beforeSingletonCreation(beanName);······// 不会尝试获取提前依赖的bean获取不到直接创建singletonObject = singletonFactory.getObject();newSingleton = true;········return singletonObject;}}
发现这里如果singletonObjects不存在该bean,会检查这个bean是否正在创建,如果还处于创建阶段,会抛出循环依赖的异常。
protected void beforeSingletonCreation(String beanName) {if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.add(beanName)) {throw new BeanCurrentlyInCreationException(beanName);}}
ObjectProvider避免强依赖
正常情况下,方法的入参bean要求必须能够在bean工厂找到,否则启动就会报错
@Beanpublic HelloService helloServiceB(@Qualifier("helloServiceA") ObjectProvider<HelloService> helloServiceA){HelloServiceB helloServiceB = new HelloServiceB();helloServiceB.setHelloServiceA(helloServiceA.getIfAvailable());return helloServiceB;}
入参ObjectProvider不要求获取到bean,当使用调用get方法时会获取bean
@Override@Nullablepublic Object getIfAvailable() throws BeansException {if (this.optional) {return createOptionalDependency(this.descriptor, this.beanName);}else {DependencyDescriptor descriptorToUse = new DependencyDescriptor(this.descriptor) {@Overridepublic boolean isRequired() {return false;}};return doResolveDependency(descriptorToUse, this.beanName, null, null);}}
属性注入不会失效
首先要明确的是@Bean注解目的是让用户能够自定义的去创建一个bean实例。不过方法入参bean需要提前进行创建。
创建bean实例发生在org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#doCreateBean
的
instanceWrapper = createBeanInstance(beanName, mbd, args);
@Bean除了创建bean实例与@Component 的方式不同外,其他的处理都是相同的。
如果是使用@Bean 注册类中使用了@Autowired等注解,那么这些注解也不会失效,同样会对对应属性进行注入。
并且在属性注入阶段,存在循环依赖依然可以借助提前暴露解决
构造参数注入
形式
public HelloServiceB(Qualifier("helloServiceA") HelloService helloServiceA) {this.helloServiceA = helloServiceA;}public HelloServiceA(Qualifier("helloServiceB")HelloService helloServiceB) {this.helloServiceB = helloServiceB;}
注意。如果有多个构造函数,默认使用无参的构造函数创建实例
指定构造函数的话,加上@Autowired
@Autowiredpublic HelloServiceA(HelloService helloServiceB) {this.helloServiceB = helloServiceB;}
循环依赖的产生
构造和使用@Bean方法产生的原因基本相同,同样需要解析入参的同样是在执行构造函数之前需要解析入参,
// Candidate constructors for autowiring?Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);if (ctors != null || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR ||mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {return autowireConstructor(beanName, mbd, ctors, args);}
同样也会对依赖的bean进行获取/创建,同样也是没有提前暴露的过程,产生循环依赖会报错。与方法暴露逻辑相同,不再重复看这个流程了。
构造注入如何避免强依赖
测试@Autowired(required = false)
@Autowired(required = false)public HelloServiceA(@Qualifier("helloServiceB") HelloService helloServiceB) {this.helloServiceB = helloServiceB;}
实测不生效
那么使用ObjectProvider呢
@Autowired(required = false)public HelloServiceA(@Qualifier("helloServiceB") ObjectProvider<HelloService> helloServiceB) {this.helloServiceB = helloServiceB.getIfAvailable();}
实测可行
属性注入不会失效
与@Bean的原因相同