我是靠谱客的博主 冷酷水池,最近开发中收集的这篇文章主要介绍Spring框架IOC容器初始化核心源码解析之五:单例Bean循环依赖解决和自动注入机制,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

填充属性

结合spring源码和 https://www.processon.com/view/link/5dec9a96e4b0c080dba0305b 上总结的流程图一起看,效果会更好。

书接上篇,继续分析populateBean(beanName, mbd, instanceWrapper);这个方法。

protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
		...

        //这儿,可以通过InstantiationAwareBeanPostProcessors.postProcessAfterInstantiation 方法,来自定义的填充bean的属性。spring的扩展点之一。
		// Give any InstantiationAwareBeanPostProcessors the opportunity to modify the
		// state of the bean before properties are set. This can be used, for example,
		// to support styles of field injection.
		boolean continueWithPropertyPopulation = true;

		if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
			for (BeanPostProcessor bp : getBeanPostProcessors()) {
				if (bp instanceof InstantiationAwareBeanPostProcessor) {
					InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
					if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
						continueWithPropertyPopulation = false;
						break;
					}
				}
			}
		}

		if (!continueWithPropertyPopulation) {
			return;
		}

        //bean的属性和值的封装。
		PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);

        //如果在bean定义中配置了自动装配,则这里面会解析自动装配对应的bean。
		if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME ||
				mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {
			MutablePropertyValues newPvs = new MutablePropertyValues(pvs);

            //byName方式自动装配
			// Add property values based on autowire by name if applicable.
			if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME) {
				autowireByName(beanName, mbd, bw, newPvs);
			}
            
            //byType方式自动装配
			// Add property values based on autowire by type if applicable.
			if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {
				autowireByType(beanName, mbd, bw, newPvs);
			}
            
            //新的属性和值对象中会包含自动装配识别的bean。
			pvs = newPvs;
		}


        //如果有 InstantiationAwareBeanPostProcessor,则会调用InstantiationAwareBeanPostProcessor.postProcessPropertyValues方法,这里面可以修改pvs,直接修改bean实例的属性等。@Autowired 注解的解析和属性注入触发点就在这儿。
		boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
		boolean needsDepCheck = (mbd.getDependencyCheck() != RootBeanDefinition.DEPENDENCY_CHECK_NONE);

		if (hasInstAwareBpps || needsDepCheck) {
			if (pvs == null) {
				pvs = mbd.getPropertyValues();
			}
			PropertyDescriptor[] filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
			if (hasInstAwareBpps) {
				for (BeanPostProcessor bp : getBeanPostProcessors()) {
					if (bp instanceof InstantiationAwareBeanPostProcessor) {
						InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
						pvs = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
						if (pvs == null) {
							return;
						}
					}
				}
			}
			if (needsDepCheck) {
				checkDependencies(beanName, mbd, filteredPds, pvs);
			}
		}
        
        //将pvs中的值注入到bean实例中去。
		if (pvs != null) {
			applyPropertyValues(beanName, mbd, bw, pvs);
		}
	}

@Autowired 解析

我们来看下最常用的 @Autowired 注解是如何实现的。在AnnotationApplicationContext实例化的第一步,往容器中注册spring内部的组件时,会注册AutowiredAnnotationBeanPostProcessor,它实现了 InstantiationAwareBeanPostProcessor,因此在上一步的属性注入中,会触发AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues 方法调用:

public PropertyValues postProcessPropertyValues(
			PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeanCreationException {
        
        //构建注入元信息
		InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);
		try {
		    //注入
			metadata.inject(bean, beanName, pvs);
		}
		...
		return pvs;
	}

简单的看下构建注入元信息方法

private InjectionMetadata findAutowiringMetadata(String beanName, Class<?> clazz, @Nullable PropertyValues pvs) {
        
        //先从缓存中拿,拿到了直接返回,没拿到就去解析构建,然后放到缓存中
		// Fall back to class name as cache key, for backwards compatibility with custom callers.
		String cacheKey = (StringUtils.hasLength(beanName) ? beanName : clazz.getName());
		// Quick check on the concurrent map first, with minimal locking.
		InjectionMetadata metadata = this.injectionMetadataCache.get(cacheKey);
		if (InjectionMetadata.needsRefresh(metadata, clazz)) {
			synchronized (this.injectionMetadataCache) {
				metadata = this.injectionMetadataCache.get(cacheKey);
				if (InjectionMetadata.needsRefresh(metadata, clazz)) {
					if (metadata != null) {
						metadata.clear(pvs);
					}
					//解析类信息,构建注入元信息。
					metadata = buildAutowiringMetadata(clazz);
					this.injectionMetadataCache.put(cacheKey, metadata);
				}
			}
		}
		return metadata;
	}

具体构建过程:

private InjectionMetadata buildAutowiringMetadata(final Class<?> clazz) {
		List<InjectionMetadata.InjectedElement> elements = new ArrayList<>();
		Class<?> targetClass = clazz;
        
        //循环解析父类。
		do {
			final List<InjectionMetadata.InjectedElement> currElements = new ArrayList<>();
            
            //doWithLocalFields简单的模板方法,这个代码块时对当前解析的类的所有字段解析,找到有注入相关注解(@Autowired @Value @Inject),包装为AutowiredFieldElement放到currElements中。
			ReflectionUtils.doWithLocalFields(targetClass, field -> {
				AnnotationAttributes ann = findAutowiredAnnotation(field);
				if (ann != null) {
					...
					boolean required = determineRequiredStatus(ann);
					currElements.add(new AutowiredFieldElement(field, required));
				}
			});

             //doWithLocalMethods同理,这个代码块时对当前解析的类的所有方法解析,找到有注入相关注解(@Autowired @Value @Inject),包装为AutowiredMethodElement放到currElements中。
			ReflectionUtils.doWithLocalMethods(targetClass, method -> {
				Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);
				if (!BridgeMethodResolver.isVisibilityBridgeMethodPair(method, bridgedMethod)) {
					return;
				}
				AnnotationAttributes ann = findAutowiredAnnotation(bridgedMethod);
				if (ann != null && method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) {
					....
					boolean required = determineRequiredStatus(ann);
					PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);
					currElements.add(new AutowiredMethodElement(method, required, pd));
				}
			});

			elements.addAll(0, currElements);
			//递归解析父类
			targetClass = targetClass.getSuperclass();
		}
		while (targetClass != null && targetClass != Object.class);

		return new InjectionMetadata(clazz, elements);
	}

注入元信息构建完成之后,接下来就是注入了:

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) {
				...
				//具体注入
				element.inject(target, beanName, pvs);
			}
		}
	}

在构建注入元信息时,属性注入元信息构建的类型是AutowiredFieldElement,方法注入元信息构建的类型是AutowiredMethodElement,因此在具体注入时,会走不同的分支,已属性注入为例【方法注入的实现思路是一致的,只不过需要解析的是方法的参数值】:

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是描述符,对依赖信息的封装。
				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 {
				    //调用beanFactory的解析依赖
					value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);
				}
				...
				
				//缓存处理,注意缓存技巧,能缓存最终结果就缓存最终结果,缓存不了就缓存中间结果。
				synchronized (this) {
					if (!this.cached) {
						if (value != null || this.required) {
							this.cachedFieldValue = desc;
							//注册依赖(两个map)
							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);
			}
		}

注入中最为关键的代码,beanFactory的resolveDependency方法:

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

		descriptor.initParameterNameDiscovery(getParameterNameDiscoverer());
		//对注入是Optional类型的支持
		if (Optional.class == descriptor.getDependencyType()) {
			return createOptionalDependency(descriptor, requestingBeanName);
		}
		//对注入是ObjectFactory和ObjectProvider类型的支持
		else if (ObjectFactory.class == descriptor.getDependencyType() ||
				ObjectProvider.class == descriptor.getDependencyType()) {
			return new DependencyObjectProvider(descriptor, requestingBeanName);
		}
		//对JSR330,javax.inject.Provider的支持
		else if (javaxInjectProviderClass == descriptor.getDependencyType()) {
			return new Jsr330ProviderFactory().createDependencyProvider(descriptor, requestingBeanName);
		}
		else {
			Object result = getAutowireCandidateResolver().getLazyResolutionProxyIfNecessary(
					descriptor, requestingBeanName);
			if (result == null) {
			    //真正的解析依赖,Optional类型,ObjectFactory和ObjectProvider类型 都是对这个的简单包装。
				result = doResolveDependency(descriptor, requestingBeanName, autowiredBeanNames, typeConverter);
			}
			return result;
		}
	}

终于要真正解析了, 找到想要的bean,注意这里面会触发对依赖bean的getBean动作,形成递归调用getBean方法:

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

		InjectionPoint previousInjectionPoint = ConstructorResolver.setCurrentInjectionPoint(descriptor);
		try {
			...
        
			Class<?> type = descriptor.getDependencyType();
			//扩展点,默认调用SimpleAutowireCandidateResolver.getSuggestedValue,返回null
			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());
				return (descriptor.getField() != null ?
						converter.convertIfNecessary(value, type, descriptor.getField()) :
						converter.convertIfNecessary(value, type, descriptor.getMethodParameter()));
			}

            //对注入的是数组、集合、Map类型的处理。
			Object multipleBeans = resolveMultipleBeans(descriptor, beanName, autowiredBeanNames, typeConverter);
			if (multipleBeans != null) {
				return multipleBeans;
			}

            //从容器中查找符合的beanDefinition。里面的逻辑大概为,先通过类型找到所有的bean,然后做一些特殊处理,比如是不是在spring的注入类型缓存中【spring框架本身没用,也算一个扩展点】,找到的beanDefinition支不支持自动注入【默认支持】等处理。
			Map<String, Object> matchingBeans = findAutowireCandidates(beanName, type, descriptor);
			if (matchingBeans.isEmpty()) {
			    //如果没有找到,并且required为true,则抛错。
				if (isRequired(descriptor)) {
					raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor);
				}
				return null;
			}

			String autowiredBeanName; //注入的beanName
			Object instanceCandidate; //注入的bean实例

			if (matchingBeans.size() > 1) {
			    //找到的beanDefinition多于一个时,先找有没有@Primary注解的,有就直接返回,再找@Priority,如果有多个,找优先级最高的那个返回;最后兜底,找候选bean中,有没有名称和注入的属性名是一样的,找到了就返回;如果都没有找到,返回null
				autowiredBeanName = determineAutowireCandidate(matchingBeans, descriptor);
				if (autowiredBeanName == null) {
				    //没有找到匹配的,并且required为true,则抛错。
					if (isRequired(descriptor) || !indicatesMultipleBeans(type)) {
						return descriptor.resolveNotUnique(type, 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) {
			    //前面的解析得出的是要注入的beanName,这个方法就是通过beanName解析出bean来,默认就是调用getBean方法。
				instanceCandidate = descriptor.resolveCandidate(autowiredBeanName, type, this);
			}
			Object result = instanceCandidate;
			...
			return result;
		}
		finally {
			ConstructorResolver.setCurrentInjectionPoint(previousInjectionPoint);
		}
	}

到这儿,基本上分析清楚了 @Autowired 是怎么完成属性的注入了(方法的注入几乎一样)。

单例bean循环依赖解决

现在,可以通过一个示例来分析下,spring是如何通过缓存暴露早期对象来解决循环依赖问题的。

说,有两个形成循环依赖的组件ComponentA和ComponentB:

@Component
@Data
public class ComponentA {

    @Autowired
    private ComponentB componentB;
}

@Component
@Data
public class ComponentB {

    @Autowired
    private ComponentA componentA;
}

跟上配置类和启动代码:

@Configuration
@ComponentScan
public class MainConfig {

}

public class Main {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MainConfig.class);
        context.registerShutdownHook();
    }
}

在分析之前,先通过DefaultSingletonBeanRegistry.getSingleton方法来认识下创建单例bean用到的3个缓存:

protected Object getSingleton(String beanName, boolean allowEarlyReference) {
        //this.singletonObjects 完整单例缓存【1级缓存】,缓存的是已经完全创建好的单例bean
		Object singletonObject = this.singletonObjects.get(beanName);
		
		//this.singletonsCurrentlyInCreation 保存当前正在创建的单例beanName,一个单例Bean只有正在创建的过程中,递归getBean自己时,才会形成循环依赖。这个属性主要用于优化
		if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
			synchronized (this.singletonObjects) {
			
			    //this.earlySingletonObjects 早期单例bean缓存【2级缓存】,缓存刚实例化出来,但还没有填充属性和初始化的单例bean。这个也是用来加速优化用的。
				singletonObject = this.earlySingletonObjects.get(beanName);
				if (singletonObject == null && allowEarlyReference) {
				
				    //this.singletonFactories 早期单例工厂对象缓存【3级缓存】,缓存获取早期单例bean的对象工厂实例。
					ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
					
					if (singletonFactory != null) {
					    //调用3级缓存中的对象工厂的getObject()方法,得到单例bean的早期实例,反手加入到二级缓存中,并将3级缓存清除。这样请求多次的时候就不用重复调用getObject方法。
						singletonObject = singletonFactory.getObject();
						this.earlySingletonObjects.put(beanName, singletonObject);
						this.singletonFactories.remove(beanName);
					}
				}
			}
		}
		return singletonObject;
	}

假如在实例化单例bean时,先实例化ComponentA,即getBean(“componentA”)做为入口进行分析,

建议看图【单例bean的循环依赖示例】:https://www.processon.com/view/link/5dec9a96e4b0c080dba0305b

那么核心的调用链:

getBean(“componentA”) -> doGetBean(“componentA”) -> getSingleton(“componentA”)【第一次调用,返回null】-> getSingleton(“componentA”, ()->createBean()) 【回调createBean的前后做一些处理,前置处理 将"componentA"加入singletonsCurrentlyInCreation中, 后置处理从singletonsCurrentlyInCreation删除"componentA",并加入完整单例缓存】

-> createBean(“componentA”) -> doCreateBean(“componentA”) -> createBeanInstance(“componentA”)【实例化"componentA",新鲜出炉,早期对象】 -> addSingletonFactory(“componentA”,早期对象包装的对象工厂) 【将早期对象"componentA"暴露到singletonFactories三级缓存中】

-> populateBean(“componentA”) -> postProcessPropertyValues(“componentA”) -> findAutowiringMetadata(“componentA”) -> resolveDependency(“componentA”) -> doResolveDependency(“componentA”)【解析到"componentA"的属性自动注入"componentB"】-> resolveCandidate(“componentB”)

-> getBean(“componentB”) -> …实例化"componentB",暴露"componentB"的早期对象到三级缓存,填充componentB属性时解析到依赖componentA,触发getBean(“componentA”)

-> getSingleton(“componentA”)【第二次调用,返回"componentA"早期对象】-> 完成componentB的属性填充,初始化componentB,加入到单例缓存中,返回componentB的完整实例 -> 完成componentA的属性填充,初始化componentA,加入到单例缓存中,返回componentA的完整实例。

autowireMode 解析

指定为byName时:

protected void autowireByName(
			String beanName, AbstractBeanDefinition mbd, BeanWrapper bw, MutablePropertyValues pvs) {
        
        //获取beanDefinition中,非简单的属性名,这些属性就是需要去进行自动注入的要处理的
		String[] propertyNames = unsatisfiedNonSimpleProperties(mbd, bw);
		for (String propertyName : propertyNames) {
			if (containsBean(propertyName)) {
			    
			    //直接根据属性名字,到容器中去getBean。
				Object bean = getBean(propertyName);
				
				//加入到pvs,在后面统一绑定到属性上。
				pvs.add(propertyName, bean);
				
				//注册依赖关系(两个依赖关系的map)
				registerDependentBean(propertyName, beanName);
				...
			}
			....
		}
	}

指定为byType时:

protected void autowireByType(
			String beanName, AbstractBeanDefinition mbd, BeanWrapper bw, MutablePropertyValues pvs) {

		TypeConverter converter = getCustomTypeConverter();
		if (converter == null) {
			converter = bw;
		}

		Set<String> autowiredBeanNames = new LinkedHashSet<>(4);
		
		//遍历所有非简单属性
		String[] propertyNames = unsatisfiedNonSimpleProperties(mbd, bw);
		for (String propertyName : propertyNames) {
			try {
			    //构建属性描述
				PropertyDescriptor pd = bw.getPropertyDescriptor(propertyName);
				// Don't try autowiring by type for type Object: never makes sense,
				// even if it technically is a unsatisfied, non-simple property.
                
                //属性的类型为Object时,byType不会理它。
				if (Object.class != pd.getPropertyType()) {
				    
				    //获取写方法参数,也就会setter方法的参数。
					MethodParameter methodParam = BeanUtils.getWriteMethodParameter(pd);
					// Do not allow eager init for type matching in case of a prioritized post-processor.
					boolean eager = !PriorityOrdered.class.isInstance(bw.getWrappedInstance());
					
					//构建依赖描述
					DependencyDescriptor desc = new AutowireByTypeDependencyDescriptor(methodParam, eager);
					
					//使用容器的resolveDependency方法进行依赖解析,这儿就和前面解析@AutoWired用到的方法一样。
					Object autowiredArgument = resolveDependency(desc, beanName, autowiredBeanNames, converter);
					
					/加入到pvs,在后面统一绑定到属性上。
					if (autowiredArgument != null) {
						pvs.add(propertyName, autowiredArgument);
					}
					
					//注册依赖关系
					for (String autowiredBeanName : autowiredBeanNames) {
						registerDependentBean(autowiredBeanName, beanName);
					    ....
					}
					autowiredBeanNames.clear();
				}
			}
			catch (BeansException ex) {
				throw new UnsatisfiedDependencyException(mbd.getResourceDescription(), beanName, propertyName, ex);
			}
		}
	}

本文主要分析了常规工作中,使用@Autowired注解时,spring是如何自动注入对应的依赖的,然后通过一个实际示例分析了spring是如果通过缓存早期对象的方式来解决单例bean的循环依赖问题的。

最后,请思考一个问题,单例bean的循环依赖问题中,如果是构造器注入的话,spring的这种方式能不能解决?为什么?在创建bean的过程中,有一步会校验多例bean的循环依赖,如果存在直接报错,spring又为什么不能解决多例bean的循环依赖问题?

最后

以上就是冷酷水池为你收集整理的Spring框架IOC容器初始化核心源码解析之五:单例Bean循环依赖解决和自动注入机制的全部内容,希望文章能够帮你解决Spring框架IOC容器初始化核心源码解析之五:单例Bean循环依赖解决和自动注入机制所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(28)

评论列表共有 0 条评论

立即
投稿
返回
顶部