【二十二】Spring filed上使用@AutoWired注解,依赖注入源码分析

一、简介

不清楚实例化bean、填充属性、初始化bean的顺序、做的事、执行了哪些扩展器的请看我以前写的这篇【十八】Spring IOC 总结之getBean主流程和各个扩展点总结

测试代码的注入方式是:直接在成员变量上用@AutoWired注解

先说重点

@Autowired在成员变量上的依赖注入是AutowiredAnnotationBeanPostProcessor来完成的

AutowiredAnnotationBeanPostProcessor处理依赖注入的整个流程概况来说就是下面三个最重要的东西来做的:

1.它实现了MergedBeanDefinitionPostProcessor,主要用到方法postProcessMergedBeanDefinition。该方法在实例化完成后调用。

该方法主要做的是:解析@Autowire注解生成注入元数据injectionMetadata。

解析出该类哪些filed和filedmethod需要依赖注入,然后放入injectionMetadataCache缓存中,待后面填充阶段的postProcessPropertyValues方法使用。

2.它继承了InstantiationAwareBeanPostProcessorAdapter,主要用到方法postProcessPropertyValues。该方法在填充阶段调用。

它根据前面解析出来的injectionMetadata来做真正的依赖注入。

3.它有个map是 Map<String, InjectionMetadata> injectionMetadataCache。key是哪个bean里面有成员需要依赖注入,这个例子中Key就是testController。value是InjectionMetadata,它保存的是该类哪些字段需要依赖注入。

二、AutowiredAnnotationBeanPostProcessor#postProcessMergedBeanDefinition方法

在bean实例化后,例子中即是testController(它里面需要注入成员变量testService)实例化后,进入填充阶段前,会调用该方法

源码:

	@Override
	public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
		if (beanType != null) {
			InjectionMetadata metadata = findAutowiringMetadata(beanName, beanType, null);
			metadata.checkConfigMembers(beanDefinition);
		}
	}

做了两件事

1.搜索该Bean内@Autowired注解的信息,生成InjectionMetadata需要依赖注入的元数据信息

2. 检查配置成员

2.1.findAutowiringMetadata方法

private InjectionMetadata findAutowiringMetadata(String beanName, Class<?> clazz, PropertyValues pvs) {
		// Fall back to class name as cache key, for backwards compatibility with custom callers.
		String cacheKey = (StringUtils.hasLength(beanName) ? beanName : clazz.getName());

         缓存中根据beanNmae获取该bean的InjectionMetadata
		// Quick check on the concurrent map first, with minimal locking.
		InjectionMetadata metadata = this.injectionMetadataCache.get(cacheKey);

       //如果metadata为null或者metadata!=clazz
		if (InjectionMetadata.needsRefresh(metadata, clazz)) {
			synchronized (this.injectionMetadataCache) {
				metadata = this.injectionMetadataCache.get(cacheKey);


                //如果metadata为null或者metadata!=clazz
				if (InjectionMetadata.needsRefresh(metadata, clazz)) {
					if (metadata != null) {
						metadata.clear(pvs);
					}
					try {
						metadata = buildAutowiringMetadata(clazz);

                        //放入缓存
						this.injectionMetadataCache.put(cacheKey, metadata);
					}
					catch (NoClassDefFoundError err) {
						throw new IllegalStateException("Failed to introspect bean class [" + clazz.getName() +
								"] for autowiring metadata: could not find class that it depends on", err);
					}
				}
			}
		}
		return metadata;
	}

做了2件事:

1.以testController(它里面需要注入成员变量testService)为KEY,在injectionMetadataCache找InjectionMetadata

那么,很不幸,第一次是找不到的。找到了就直接返回了

2.找不到那就要自己创建InjectionMetadata了,然后再放入injectionMetadataCache中。自己创建对应的方法就是源码里面的buildAutowiringMetadata方法

这里用了个双重锁机制。

2.1.1 buildAutowiringMetadata方法

private InjectionMetadata buildAutowiringMetadata(final Class<?> clazz) {
		LinkedList<InjectionMetadata.InjectedElement> elements = new LinkedList<InjectionMetadata.InjectedElement>();
		Class<?> targetClass = clazz;

		do {
			final LinkedList<InjectionMetadata.InjectedElement> currElements =
					new LinkedList<InjectionMetadata.InjectedElement>();

           遍历这个类中的所有filed
			ReflectionUtils.doWithLocalFields(targetClass, new ReflectionUtils.FieldCallback() {
				@Override
				public void doWith(Field field) throws IllegalArgumentException, IllegalAccessException {

                    //获取filed是否带了@AutoWire标签
					AnnotationAttributes ann = findAutowiredAnnotation(field);
					if (ann != null) {

                         //过滤掉static的filed
						if (Modifier.isStatic(field.getModifiers())) {
							if (logger.isWarnEnabled()) {
								logger.warn("Autowired annotation is not supported on static fields: " + field);
							}
							return;
						}

                        /这里就取了Autowired的一个required属性,这个属性的作用是
                    //如果这个是false就表明在自动装配的时候没有发现又对应的实例
                    //就跳过去,如果是true没有发现有与之匹配的就会抛出个异常,仅此而已
						boolean required = determineRequiredStatus(ann);
						currElements.add(new AutowiredFieldElement(field, required));
					}
				}
			});


            //遍历这个类中的所有filedmethiod
			ReflectionUtils.doWithLocalMethods(targetClass, new ReflectionUtils.MethodCallback() {
				@Override
				public void doWith(Method method) throws IllegalArgumentException, IllegalAccessException {


                     /**
                 * 这里获取一个桥接的方法对象
                 * 1,遍历class里面所有的method方法,findBridgedMethod方法会获取method方法的声明的类,
                 * 并且将该类下面所有的方法形成数组,然后遍历数组跟method比较,如果方法不同,但是方法的
                 * 名称和参数数量相同,则视为桥接方法返回
                 */
					Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);

                   //如果桥接方法和method不同,则直接返回
					if (!BridgeMethodResolver.isVisibilityBridgeMethodPair(method, bridgedMethod)) {
						return;
					}

                   //获取method是否带了@AutoWire标签
					AnnotationAttributes ann = findAutowiredAnnotation(bridgedMethod);
					if (ann != null && method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) {

                        //同样过滤静态方法
						if (Modifier.isStatic(method.getModifiers())) {
							if (logger.isWarnEnabled()) {
								logger.warn("Autowired annotation is not supported on static methods: " + method);
							}
							return;
						}

                        //参数数量0也过滤,注入set参数
						if (method.getParameterTypes().length == 0) {
							if (logger.isWarnEnabled()) {
								logger.warn("Autowired annotation should only be used on methods with parameters: " +
										method);
							}
						}
						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);
	}

做了4件事:

1.遍历这个类所有的Filed

获取带了@Autowire注解的filed,过滤掉static的filed,解析这些@Autowire是否为requird

2.便利这个类所有的filedmethod,找到哪些方法里面用了需要依赖注入的bean的,找到桥接方法。

如果桥接方法和method不同则直接返回。

找到哪些方法有@Autowire标签,过来静态方法,过滤参数数量为0的方法,注入set参数。

3.找到该类的父类继续前两步操作。

4.返回InjectionMetadata。

三、AutowiredAnnotationBeanPostProcessor#postProcessPropertyValues

源码:

	@Override
	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);
		}
		catch (BeanCreationException ex) {
			throw ex;
		}
		catch (Throwable ex) {
			throw new BeanCreationException(beanName, "Injection of autowired dependencies failed", ex);
		}
		return pvs;
	}

做了2件事:

1.从该类中得到需要依赖注入的元数据

2.调用metadata.inject方法执行依赖注入

3.1 metadata.inject方法执行依赖注入

	public void inject(Object target, String beanName, PropertyValues pvs) throws Throwable {
		Collection<InjectedElement> elementsToIterate =
				(this.checkedElements != null ? this.checkedElements : this.injectedElements);
		if (!elementsToIterate.isEmpty()) {
			boolean debug = logger.isDebugEnabled();
			for (InjectedElement element : elementsToIterate) {
				if (debug) {
					logger.debug("Processing injected element of bean '" + beanName + "': " + element);
				}
				element.inject(target, beanName, pvs);
			}
		}
	}

循环调用AutowiredAnnotationBeanPostProcessor#inject进行依赖注入

@Override
		protected void inject(Object bean, String beanName, 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<String>(1);
				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)) {
									if (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);
			}
		}
	}

做了3件事:

1.解析依赖DefaultListableBeanFactory#beanFactory.resolveDependency

其实主要就是找到依赖。这里后面有空详细介绍,赶着出门买菜

2.注册依赖registerDependentBeans

实际上就是写入DefaultListableBeanFactory类的两个MAP中

dependentBeanMap,key是例子中的testServiceImpl,value数组是哪些bean依赖了它,这里的value数组中就只有testController

dependenciesForBeanMap,key是例子中的testController,value数组是testController依赖了哪些bean,这里的value数组就只有testServiceImpl

3.通过反射为属性赋值

3.1.1  DefaultListableBeanFactory#beanFactory.resolveDependency

 源码:

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

        // ParameterNameDiscovery用于解析方法参数名称
		descriptor.initParameterNameDiscovery(getParameterNameDiscoverer());

         // 1. Optional<T>
		if (javaUtilOptionalClass == descriptor.getDependencyType()) {
			return new OptionalDependencyFactory().createOptionalDependency(descriptor, requestingBeanName);
		}

        // 2. ObjectFactory<T>、ObjectProvider<T>
		else if (ObjectFactory.class == descriptor.getDependencyType() ||
				ObjectProvider.class == descriptor.getDependencyType()) {
			return new DependencyObjectProvider(descriptor, requestingBeanName);
		}

        // 3. javax.inject.Provider<T>
		else if (javaxInjectProviderClass == descriptor.getDependencyType()) {
			return new Jsr330ProviderFactory().createDependencyProvider(descriptor, requestingBeanName);
		}
		else {

            // 4. @Lazy
			Object result = getAutowireCandidateResolver().getLazyResolutionProxyIfNecessary(
					descriptor, requestingBeanName);

             // 5. 正常情况
			if (result == null) {
				result = doResolveDependency(descriptor, requestingBeanName, autowiredBeanNames, typeConverter);
			}
			return result;
		}
	}

做了2件事:

1.初始参数名称发现

2.根据各种不同的依赖类型( Optional、延迟注入、懒加载)解析依赖并返回。

本场就就是走的最后的doResolvDependency

doResolvDependency源码:

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

		InjectionPoint previousInjectionPoint = ConstructorResolver.setCurrentInjectionPoint(descriptor);
		try {

            // 1. 快速查找,根据名称查找。AutowiredAnnotationBeanPostProcessor用到
			Object shortcut = descriptor.resolveShortcut(this);
			if (shortcut != null) {
				return shortcut;
			}

            // 2. 注入指定值,QualifierAnnotationAutowireCandidateResolver解析@Value会用到
			Class<?> type = descriptor.getDependencyType();
			Object value = getAutowireCandidateResolver().getSuggestedValue(descriptor);
			if (value != null) {
				if (value instanceof String) {

                    // 2.1 占位符解析
					String strVal = resolveEmbeddedValue((String) value);
					BeanDefinition bd = (beanName != null && containsBean(beanName) ? getMergedBeanDefinition(beanName) : null);

                    // 2.2 Spring EL 表达式
					value = evaluateBeanDefinitionString(strVal, bd);
				}
				TypeConverter converter = (typeConverter != null ? typeConverter : getTypeConverter());

                // 2.3 类型转换
				return (descriptor.getField() != null ?
						converter.convertIfNecessary(value, type, descriptor.getField()) :
						converter.convertIfNecessary(value, type, descriptor.getMethodParameter()));
			}


            // 3. 集合依赖,如 Array、List、Set、Map。内部查找依赖也是使用findAutowireCandidates
			Object multipleBeans = resolveMultipleBeans(descriptor, beanName, autowiredBeanNames, typeConverter);
			if (multipleBeans != null) {
				return multipleBeans;
			}

 
             // 4. 单个依赖查询
			Map<String, Object> matchingBeans = findAutowireCandidates(beanName, type, descriptor);

            // 4.1 没有查找到依赖,判断descriptor.require
			if (matchingBeans.isEmpty()) {
				if (isRequired(descriptor)) {
					raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor);
				}
				return null;
			}

			String autowiredBeanName;
			Object instanceCandidate;


            // 4.2 有多个,如何过滤
			if (matchingBeans.size() > 1) {

                // 4.2.1 @Primary -> @Priority -> 方法名称或字段名称匹配 
				autowiredBeanName = determineAutowireCandidate(matchingBeans, descriptor);

                // 4.2.2 根据是否必须,抛出异常。注意这里如果是集合处理,则返回null
				if (autowiredBeanName == null) {
					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();
			}


            // 4.3 到了这,说明有且仅有命中一个
			if (autowiredBeanNames != null) {
				autowiredBeanNames.add(autowiredBeanName);
			}

            // 4.4 descriptor.resolveCandidate实际上调用 getBean(autowiredBeanName, type)。
			return (instanceCandidate instanceof Class ?
					descriptor.resolveCandidate(autowiredBeanName, type, this) : instanceCandidate);
		}
		finally {
			ConstructorResolver.setCurrentInjectionPoint(previousInjectionPoint);
		}
	}

doResolveDependency 封装了依赖查找的各种情况:

1)快速查找: @Autowired 注解处理场景。AutowiredAnnotationBeanPostProcessor 处理 @Autowired 注解时,如果注入的对象只有一个,会将该 bean 对应的名称缓存起来,下次直接通过名称查找会快很多。

2)注入指定值:@Value 注解处理场景。QualifierAnnotationAutowireCandidateResolver 处理 @Value 注解时,会读取 @Value 对应的值进行注入。如果是 String 要经过三个过程:①占位符处理 -> ②EL 表达式解析 -> ③类型转换,这也是一般的处理过程,BeanDefinitionValueResolver 处理 String 对象也是这个过程。

3)集合依赖查询:直接全部委托给 resolveMultipleBeans 方法。

4) 单个依赖查询:先调用 findAutowireCandidates 查找容器中所有可用的依赖,如果有多个依赖,则根据规则匹配: @Primary -> @Priority -> ③方法名称或字段名称

而findAutowireCandidates的内部逻辑是:

1.先查找 Spring IoC 内部依赖 resolvableDependencies。

在 AbstractApplicationContext#prepareBeanFactory 方法中默认设置了如下内部依赖:BeanFactory、ResourceLoader、ApplicationEventPublisher、ApplicationContext。

2.在父子容器进行类型查找:查找类型匹配的 beanNames。

循环调用beanFactory#beanNamesForType 方法根据类型查找先匹配单例实例类型(包括 Spring 托管 Bean),再匹配 BeanDefinition 的类型

这里可以看到 Spring 依赖注入的另外两个来源:一是 Spring 托管的外部 Bean,二是 Spring BeanDefinition。 

3.补偿机制

如果依赖查找无法匹配,Spring 提供了两种补偿机制。

先使用泛型补偿,不允许自身引用补偿:即 fallbackDescriptor。此时如果是集合依赖,对象必须是 @Qualifier 类型。

允许泛型补偿和自身引用补偿:但如果是集合依赖,必须过滤自己本身,即 beanName.equals(candidate) 必须剔除。

 

"Unsatisfied dependency expressed through field 'xxx'"问题通常是由于Spring容器无法找到或创建某个Bean所引起的。这通常是因为您使用注解或配置有误,导致Spring无法正确创建Bean实例。 以下是一些常见的解决方法: 1. 检查依赖是否正确注入:检查`@Autowired`或`@Resource`注解是否正确使用,确保依赖被正确注入。如果依赖是通过构造函数注入的,确保构造函数的参数和Bean的名称或类型匹配。 2. 检查Bean的定义:检查Bean的定义,确保它们被正确配置和注册。如果使用XML配置文件,则检查XML文件中的Bean定义是否正确。如果使用JavaConfig,则确保@Configuration注解和@Bean注解正确使用。 3. 检查包扫描路径:如果您使用的是@ComponentScan注解来扫描Bean,确保它们被正确扫描到。检查包路径是否正确,确保Bean所在的类上正确地使用了@Component或其他相关注解。 4. 检查Bean的作用域:如果Bean的作用域是prototype,则每次注入都会创建一个新的实例。如果您意图使用单例,则将作用域更改为singleton。 5. 检查Bean的依赖:如果Bean的依赖是其他Bean,确保这些Bean已经正确地注入和初始化了。 6. 检查Bean的依赖顺序:如果Bean之间存在依赖关系,则确保这些Bean的依赖顺序正确,以确保依赖的Bean已经被正确初始化。 通过这些方法,您应该可以解决“Unsatisfied dependency expressed through field 'xxx'”问题。如果问题仍然存在,请检查日志文件,查看详细的错误信息,以便更好地定位问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值