什么是循环依赖
说白了就是对象之间的依赖关系成环 例如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 {
@Autowired
private TestService testService;
private String name;
public TestController(){
this.name= testService.getName();
}
}
这段代码执行时会报NPE。Java类会先执行构造函数,然后在通过@Autowired注入实例,二构造函数里面需要注入的对象,因此在执行构造函数的时候就会报错。 2、还可能回导致循环依赖,即A里面注入B,B里面又注入A。(构造注入会启动时就会报错及时发现) 注:在代码中发现构造方法中注入了很多依赖,显得很臃肿,对于这个问题,说明类中有太多的责任,违反了类的单一性职责原则,这时候需要考虑使用单一职责原则进行代码重构。
属性注入对循环依赖的处理
首先说明属性注入对于循环依赖是容忍的,正常情况下出现循环依赖并不会报错,程序正常启动运行
bean工厂的三级缓存
默认bean工厂实现为DefaultListableBeanFactory 其有一个父类为DefaultSingletonBeanRegistry 其中有大名鼎鼎的三级缓存
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);
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) {
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) {
singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
throw ex;
}
}
那么如果获取不到,先判断singletonsCurrentlyInDestruction,变量名看事如果这个变量正在被销毁,那么抛出异常,继续来到beforeSingletonCreation方法
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
BeanWrapper instanceWrapper = null;
if (instanceWrapper == null) {
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
@Override
public 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中
Object sharedInstance = getSingleton(beanName);
先尝试获取bean org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#getSingleton(java.lang.String, boolean)
@Nullable
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
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);
}
}
}
}
}
}
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
@Override
public 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
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都会提前暴露生成代理,只有循环依赖才会提前暴露)
@Override
public 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注解注入循环依赖的产生
例子
@Bean
public HelloService helloServiceA(@Qualifier("helloServiceB") HelloService helloServiceB){
HelloServiceA helloServiceA = new HelloServiceA();
helloServiceA.setHelloServiceB(helloServiceB);
return helloServiceA;
}
@Bean
public 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) {
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
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);
}
}
}
}
}
}
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);
······
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工厂找到,否则启动就会报错
@Bean
public HelloService helloServiceB(@Qualifier("helloServiceA") ObjectProvider<HelloService> helloServiceA){
HelloServiceB helloServiceB = new HelloServiceB();
helloServiceB.setHelloServiceA(helloServiceA.getIfAvailable());
return helloServiceB;
}
入参ObjectProvider不要求获取到bean,当使用调用get方法时会获取bean
@Override
@Nullable
public Object getIfAvailable() throws BeansException {
if (this.optional) {
return createOptionalDependency(this.descriptor, this.beanName);
}
else {
DependencyDescriptor descriptorToUse = new DependencyDescriptor(this.descriptor) {
@Override
public 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
@Autowired
public HelloServiceA(HelloService helloServiceB) {
this.helloServiceB = helloServiceB;
}
循环依赖的产生
构造和使用@Bean方法产生的原因基本相同,同样需要解析入参的同样是在执行构造函数之前需要解析入参,
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的原因相同
|