文档章节

Spring5 依赖注入和循环依赖处理

小小明1995
 小小明1995
发布于 01/29 22:55
字数 1090
阅读 135
收藏 0

//TODO 依赖注入待补充


循环依赖处理

怎么检测是否存在循环依赖

检测循环依赖相对比较容易,Bean在创建的时候可以给该Bean打标,如果递归调用回来发现正在创建中的话,即说明了循环依赖了。

进行处理

Spring的单例对象的初始化主要分为三步(前在AbstractAutowireCapableBeanFactory#doCreateBean):

  1. createBeanInstance:实例化,其实也就是调用对象的构造方法实例化对象
  2. populateBean:填充属性,这一步主要是多Bean的依赖属性进行填充
  3. initializeBean:初始化Bean。

从上面单例bean的初始化可以知道: 依赖主要发生在第一、二步,也就是构造器依赖和field依赖。如果发生了循环依赖,构造器方式无解,field循环依赖可以通过将初始化分为两个阶段进行解决。即先对对象实例化,待循环依赖的对象属性填充完之后,再进行自身的属性填充。

对于单例对象来说,在Spring容器整个生命周期内,有且只有一个对象,所以很容易想到对象应该存在Cache中。同时,Spring为了解决单例的循环依赖问题,使用了三个容器做缓存在DefaultSingletonBeanRegistry对象中进行保存:

  1. singletonObjects : 用于存放完全初始化好的 bean
  2. earlySingletonObjects:存放原始的 bean 对象(尚未填充属性),用于解决循环依赖
  3. singletonFactories:存放 bean 工厂对象,用于解决循环依赖
在populateBean()中进行依赖注入(Autowired/Resource)

AbstractAutowireCapableBeanFactory

protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
	// ...
	
	// 是否有注入的Bean属性
	boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
	boolean needsDepCheck = (mbd.getDependencyCheck() != AbstractBeanDefinition.DEPENDENCY_CHECK_NONE);

	PropertyDescriptor[] filteredPds = null;
	if (hasInstAwareBpps) {
		if (pvs == null) {
			pvs = mbd.getPropertyValues();
		}
		//getBeanPostProcessors 返回一系列BeanPostProcessor处理器
		for (BeanPostProcessor bp : getBeanPostProcessors()) {
			if (bp instanceof InstantiationAwareBeanPostProcessor) {
				InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
				//
				PropertyValues pvsToUse = ibp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
				if (pvsToUse == null) {
					if (filteredPds == null) {
						filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
					}
					pvsToUse = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
					if (pvsToUse == null) {
						return;
					}
				}
				pvs = pvsToUse;
			}
		}
	}
	//...

AutowiredAnnotationBeanPostProcessor

/**
 * 属性注入处理
 */
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
	InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);
	try {
		// 进行属性的注入
		metadata.inject(bean, beanName, pvs);
	}
	catch (BeanCreationException ex) {
		throw ex;
	}
	catch (Throwable ex) {
		throw new BeanCreationException(beanName, "Injection of autowired dependencies failed", ex);
	}
	return pvs;
}

InjectionMetadata

/**
 * 注入
 */
public void inject(Object target, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
	Collection<InjectedElement> checkedElements = this.checkedElements;
	Collection<InjectedElement> elementsToIterate =
		(checkedElements != null ? checkedElements : this.injectedElements);
	if (!elementsToIterate.isEmpty()) {
		for (InjectedElement element : elementsToIterate) {
			if (logger.isTraceEnabled()) {
				logger.trace("Processing injected element of bean '" + beanName + "': " + element);
			}
			//调用注入
			element.inject(target, beanName, pvs);
		}
	}
}

AutowiredAnnotationBeanPostProcessor

protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
	Field field = (Field) this.member;
	//要被注入的对象
	Object value;
	if (this.cached) {
		value = resolvedCachedArgument(beanName, this.cachedFieldValue);
	}
	else {
		DependencyDescriptor desc = new DependencyDescriptor(field, this.required);
		desc.setContainingClass(bean.getClass());
		Set<String> autowiredBeanNames = new LinkedHashSet<>(1);
		Assert.state(beanFactory != null, "No BeanFactory available");
		TypeConverter typeConverter = beanFactory.getTypeConverter();
		try {
			value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);
		}
		catch (BeansException ex) {
			throw new UnsatisfiedDependencyException(null, beanName, new InjectionPoint(field), ex);
		}
		synchronized (this) {
			if (!this.cached) {
				if (value != null || this.required) {
					this.cachedFieldValue = desc;
					registerDependentBeans(beanName, autowiredBeanNames);
					if (autowiredBeanNames.size() == 1) {
						String autowiredBeanName = autowiredBeanNames.iterator().next();
						if (beanFactory.containsBean(autowiredBeanName) &&
							beanFactory.isTypeMatch(autowiredBeanName, field.getType())) {
							this.cachedFieldValue = new ShortcutDependencyDescriptor(
								desc, autowiredBeanName, field.getType());
						}
					}
				}
				else {
					this.cachedFieldValue = null;
				}
				this.cached = true;
			}
		}
	}
	if (value != null) {
		ReflectionUtils.makeAccessible(field);
		field.set(bean, value);
	}
}
}

DefaultListableBeanFactory#doResolveDependency 循环依赖解决

public Object doResolveDependency(DependencyDescriptor descriptor, @Nullable String beanName,
								  @Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {

	InjectionPoint previousInjectionPoint = ConstructorResolver.setCurrentInjectionPoint(descriptor);
	try {
		Object shortcut = descriptor.resolveShortcut(this);
		if (shortcut != null) {
			return shortcut;
		}

		Class<?> type = descriptor.getDependencyType();
		Object value = getAutowireCandidateResolver().getSuggestedValue(descriptor);
		if (value != null) {
			if (value instanceof String) {
				String strVal = resolveEmbeddedValue((String) value);
				BeanDefinition bd = (beanName != null && containsBean(beanName) ?
									 getMergedBeanDefinition(beanName) : null);
				value = evaluateBeanDefinitionString(strVal, bd);
			}
			TypeConverter converter = (typeConverter != null ? typeConverter : getTypeConverter());
			try {
				return converter.convertIfNecessary(value, type, descriptor.getTypeDescriptor());
			}
			catch (UnsupportedOperationException ex) {
				// A custom TypeConverter which does not support TypeDescriptor resolution...
				return (descriptor.getField() != null ?
						converter.convertIfNecessary(value, type, descriptor.getField()) :
						converter.convertIfNecessary(value, type, descriptor.getMethodParameter()));
			}
		}

		Object multipleBeans = resolveMultipleBeans(descriptor, beanName, autowiredBeanNames, typeConverter);
		if (multipleBeans != null) {
			return multipleBeans;
		}

		Map<String, Object> matchingBeans = findAutowireCandidates(beanName, type, descriptor);
		if (matchingBeans.isEmpty()) {
			if (isRequired(descriptor)) {
				raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor);
			}
			return null;
		}

		String autowiredBeanName;
		Object instanceCandidate;

		if (matchingBeans.size() > 1) {
			autowiredBeanName = determineAutowireCandidate(matchingBeans, descriptor);
			if (autowiredBeanName == null) {
				if (isRequired(descriptor) || !indicatesMultipleBeans(type)) {
					return descriptor.resolveNotUnique(descriptor.getResolvableType(), matchingBeans);
				}
				else {
					// In case of an optional Collection/Map, silently ignore a non-unique case:
					// possibly it was meant to be an empty collection of multiple regular beans
					// (before 4.3 in particular when we didn't even look for collection beans).
					return null;
				}
			}
			instanceCandidate = matchingBeans.get(autowiredBeanName);
		}
		else {
			// We have exactly one match.
			Map.Entry<String, Object> entry = matchingBeans.entrySet().iterator().next();
			autowiredBeanName = entry.getKey();
			instanceCandidate = entry.getValue();
		}

		if (autowiredBeanNames != null) {
			autowiredBeanNames.add(autowiredBeanName);
		}
		if (instanceCandidate instanceof Class) {
			instanceCandidate = descriptor.resolveCandidate(autowiredBeanName, type, this);
		}
		Object result = instanceCandidate;
		if (result instanceof NullBean) {
			if (isRequired(descriptor)) {
				raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor);
			}
			result = null;
		}
		if (!ClassUtils.isAssignableValue(type, result)) {
			throw new BeanNotOfRequiredTypeException(autowiredBeanName, type, instanceCandidate.getClass());
		}
		return result;
	}
	finally {
		ConstructorResolver.setCurrentInjectionPoint(previousInjectionPoint);
	}
}

populateBean 注入属性 doGetBean->getSingleton 删除bean缓存

© 著作权归作者所有

小小明1995
粉丝 0
博文 41
码字总数 26098
作品 0
济南
程序员
私信 提问
加载中

评论(0)

Spring的这七大问题,验证你能否进大厂!

  当程序员当的越久,接触的越多,就会越“迷茫”。像我,分布式好像懂一点,源码也好像懂一点。技术栈越来越多,但是好像哪一点也不精通,就会代码写得越多越“迷茫”。我可以很负责任的告...

java进阶架构师
2019/11/13
0
0
Spring 循环引用 ——理解singleton与prototype初始化的区别

所谓的循环引用,就是A依赖B,B又依赖A,A与B两个对象相互持有。像下面这种情况: class A{B b;public A(B b) {this.b=b;}} class B{A a;public B(A a ){this.a=a;} }我们知道spring在获取对...

非沧海一粟不随波逐流
2016/12/19
93
0
[Spring] 深度解析系列 (5) 番外- 循环依赖

在Spring的面试中,经常会被问到的一个问题,就是Spring是如何解决循环依赖的。 之前也有说过Spring解决循环依赖也只是在单例中,prototype 是无法解决的。 循环依赖指的是循环引用,就是两个...

起个名忒难
2019/12/18
0
0
springboot-springboot2.1.x报错循环依赖问题

前言 实际开发中,我们常常是基于模块分工开发的,也就是不同的人负责不同的模块。最后合并代码。这种方式适合多人协同,每个人只关心自己的业务模块实现(controller/model/service/mapper...

JackFace
2019/11/27
56
0
Spring基础系列-Spring事务不生效的问题与循环依赖问题

原创作品,可以转载,但是请标注出处地址:https://www.cnblogs.com/V1haoge/p/9476550.html 一、提出问题   不知道你是否遇到过这样的情况,在ssm框架中开发web引用,或者使用springboot开...

唯一浩哥
2018/08/14
0
0

没有更多内容

加载失败,请刷新页面

加载更多

REST API服务为验证失败返回的适当HTTP状态代码是什么?

每当我在基于Django / Piston的REST API应用程序中遇到验证失败时,我目前正在返回401 Unauthorized。 看过HTTP状态代码注册表后我不相信这是验证失败的合适代码,你们都推荐什么? 400错误请...

javail
12分钟前
61
0
《计算机程序的构造和解释》分享下载

书籍信息 书名:《计算机程序的构造和解释》 原作名:Structure and Interpretation of Computer Programs 作者: Harold Abelson / Gerald Jay Sussman / Julie Sussman 豆瓣评分:9.5分(22...

开始以后_
17分钟前
45
0
《Linux就该这么学》第六节课while循环语句,case测试语句,计划任务及用户文件的相关命令

《Linux就该这么学》 本书是由全国多名红帽架构师(RHCA)基于最新Linux系统共同编写的高质量Linux技术自学教程,极其适合用于Linux技术入门教程或讲课辅助教材,目前是国内最值得去读的Lin...

溪风之殇
26分钟前
44
0
有没有办法让非root进程绑定到Linux上的“特权”端口?

在我的开发盒上有这个限制是非常烦人的,因为除了我之外不会有任何用户。 我知道标准的解决方法 ,但它们都没有完全符合我的要求: authbind (Debian测试中的版本,1.0,仅支持IPv4) 使用i...

技术盛宴
27分钟前
44
0
Java程序员必须要了解的类Unsafe

前言 Java是一个安全的编程语言,它能最大程度的防止程序员犯一些低级的错误(大部分是和内存管理有关的)。但凡是不是绝对的,使用Unsafe程序员就可以操作内存,因此可能带来一个安全隐患。...

Onegoleya
27分钟前
42
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部