IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> 依赖注入的三种方式和循环依赖的产生 -> 正文阅读

[Java知识库]依赖注入的三种方式和循环依赖的产生

什么是循环依赖

说白了就是对象之间的依赖关系成环
例如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
其中有大名鼎鼎的三级缓存

        /*存放已经完成创建的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 是否提前暴露,是否成立有两个条件

  1. 判断是否允许循环依赖,如果不允许肯定不会提前暴露
  2. 另外还需要判断当前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中

	// Eagerly check singleton cache for manually registered singletons.
		Object sharedInstance = getSingleton(beanName);

先尝试获取bean
org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#getSingleton(java.lang.String, boolean)

@Nullable
	protected Object getSingleton(String beanName, boolean allowEarlyReference) {
		// Quick check for existing instance without full singleton lock
		Object 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 lock
					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

		// 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都会提前暴露生成代理,只有循环依赖才会提前暴露)

@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) {
		// Quick check for existing instance without full singleton lock
		Object 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 lock
					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);
			  ······
               // 不会尝试获取提前依赖的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工厂找到,否则启动就会报错

 @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方法产生的原因基本相同,同样需要解析入参的同样是在执行构造函数之前需要解析入参,

	// 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的原因相同

  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2022-09-25 23:07:16  更:2022-09-25 23:07:56 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/23 9:04:30-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码