Spring源码学习(八)-- 依赖注入源码解析(下)

resolveDependency()实现

 

 上篇文章分析了Spring中的自动注入(byName,byType)和@Autowired注解的工作原理以及源码,@Autowired注解依赖注入其中注入点注入,无论是属性注入还是方法注入都有一个相同的方法

org.springframework.beans.factory.support.DefaultListableBeanFactory# resolveDependency

@Nullable
Object resolveDependency(DependencyDescriptor descriptor, @Nullable String requestingBeanName,
		@Nullable Set autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException;

该方法表示,传入一个依赖描述(DependencyDescriptor),该方法会根据该依赖描述从BeanFactory中找出对应的唯一的一个Bean对象。

下面来分析一下DefaultListableBeanFactory中**resolveDependency()**方法的具体实现:

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

		// 设置parameterNameDiscoverer,用来获取方法入参名字的
        // Bean工厂的默认值为:private ParameterNameDiscoverer parameterNameDiscoverer = new DefaultParameterNameDiscoverer();
		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);
		}
		else if (javaxInjectProviderClass == descriptor.getDependencyType()) {
			return new Jsr330Factory().createDependencyProvider(descriptor, requestingBeanName);
		}
// 这个应该是我们觉得部分触及到的,其实不管何种方式,最终都是交给doResolveDependency方法去处理了
		else {
			// 在属性或set方法参数上使用了@Lazy注解,那么则构造一个代理对象并返回,真正使用该代理对象时才进行类型筛选Bean
			Object result = getAutowireCandidateResolver().getLazyResolutionProxyIfNecessary(
					descriptor, requestingBeanName);
			if (result == null) {
				// descriptor表示某个属性或某个set方法
				// requestingBeanName表示正在进行依赖注入的Bean
				result = doResolveDependency(descriptor, requestingBeanName, autowiredBeanNames, typeConverter);
			}
			return result;
		}
	}

对一些特殊的类型进行特殊处理,一般的通用处理都会调用 doResolveDependency 方法。

Object result = getAutowireCandidateResolver().getLazyResolutionProxyIfNecessary(
					descriptor, requestingBeanName);

判断注入的字段或者方法参数有没有@Lazy注解,getAutowireCandidateResolver()得到ContextAnnotationAutowireCandidateResolver,getLazyResolutionProxyIfNecessary方法:

Spring源码学习(八)-- 依赖注入源码解析(下)_第1张图片

 如果是@Lazy 注解的注入,则返回的不是具体实例,而是一个代理对象,赋值为该属性。

如果是普通的@Autowired注解 ,则会调用 doResolveDependency 方法。

 如果当前descriptor之前做过依赖注入了,则可以直接取shortcut了,相当于缓存,简单的说就是去Bean工厂的缓存里去看看,有没有名称为此的Bean,有就直接返回,没必要继续往下走了

Object value = getAutowireCandidateResolver().getSuggestedValue(descriptor);

@value注解的处理:

getAutowireCandidateResolver()得到ContextAnnotationAutowireCandidateResolver,getSuggestedValue方法,具体实现在父类 QualifierAnnotationAutowireCandidateResolver中:

Spring源码学习(八)-- 依赖注入源码解析(下)_第2张图片

 判断注入的字段或者方法参数有没有@Value注解,有的话拿到@Value注解的value,没有则返回null

Spring源码学习(八)-- 依赖注入源码解析(下)_第3张图片

 拿到@Value注解的value值不为null,首先进行占位符填充(通过Environment),之后解析Spring表达式(#{}),如果需要会进行类型转换后返回结果

之后是对数组、Collection、Map等类型进行处理,也是支持自动注入的

 因为是数组或容器,Sprng可以直接把符合类型的bean都注入到数组或容器中,处理逻辑是:

1.确定容器或数组的组件类型 if else 分别对待,分别处理

2.调用findAutowireCandidates(核心方法)方法,获取与组件类型匹配的Map(beanName -> bean实例)

3.将符合beanNames添加到autowiredBeanNames中

如果不是集合数组类型的,继续走:

Map matchingBeans = findAutowireCandidates(beanName, type, descriptor);

获取所有【类型】匹配的Beans,形成一个Map(此处用Map装,是因为可能不止一个符合条件,key是beanName,value有可能是bean对象,也有可能是beanclass),该方法就特别重要了,对泛型类型的匹配、对@Qualifierd的解析都在这里面,下面详情分解

Spring源码学习(八)-- 依赖注入源码解析(下)_第4张图片

如果没有符合条件的bean,并且required为true,抛出异常

如果根据类型找到了多个Bean,进一步筛选出某一个

Spring源码学习(八)-- 依赖注入源码解析(下)_第5张图片

 determineAutowireCandidate方法 从多个Bean中,筛选出一个符合条件的Bean:

	@Nullable
	protected String determineAutowireCandidate(Map candidates, DependencyDescriptor descriptor) {
		Class requiredType = descriptor.getDependencyType();
		// candidates表示根据类型所找到的多个Bean,判断这些Bean中是否有一个是@Primary的
		String primaryCandidate = determinePrimaryCandidate(candidates, requiredType);
		if (primaryCandidate != null) {
			return primaryCandidate;
		}
		// 取优先级最高的Bean
		String priorityCandidate = determineHighestPriorityCandidate(candidates, requiredType);
		if (priorityCandidate != null) {
			return priorityCandidate;
		}
		// Fallback
		// 匹配descriptor的名字,要么是字段的名字,要么是set方法入参的名字
		for (Map.Entry entry : candidates.entrySet()) {
			String candidateName = entry.getKey();
			Object beanInstance = entry.getValue();
			if ((beanInstance != null && this.resolvableDependencies.containsValue(beanInstance)) ||
					matchesBeanName(candidateName, descriptor.getDependencyName())) {
				return candidateName;
			}
		}
		return null;
	}

首先调用determinePrimaryCandidate方法,判断找到的多个bean中是否有一个标记了@Primary注解的,看一下determinePrimaryCandidate方法:

	protected String determinePrimaryCandidate(Map candidates, Class requiredType) {
		String primaryBeanName = null;
		for (Map.Entry entry : candidates.entrySet()) {
			String candidateBeanName = entry.getKey();
			Object beanInstance = entry.getValue();
			// isPrimary就是去看看容器里(包含父容器)对应的Bean定义信息是否有@Primary标注
			if (isPrimary(candidateBeanName, beanInstance)) {
				if (primaryBeanName != null) {
					boolean candidateLocal = containsBeanDefinition(candidateBeanName);
					boolean primaryLocal = containsBeanDefinition(primaryBeanName);

					// 这个相当于如果已经找到了一个@Primary的,然后又找到了一个 那就抛出异常
					// @Primary只能标注到一个同类型的Bean上
					if (candidateLocal && primaryLocal) {
						throw new NoUniqueBeanDefinitionException(requiredType, candidates.size(),
								"more than one 'primary' bean found among candidates: " + candidates.keySet());
					}
					else if (candidateLocal) {
						primaryBeanName = candidateBeanName;
					}
				}
				// 把找出来的标注了@Primary的Bean的名称返回出去
				else {
					primaryBeanName = candidateBeanName;
				}
			}
		}
		return primaryBeanName;
	}

如果找到了一个@Primary标记的Bean,直接返回,由此可见,@Primary的优先级还是非常的高的

如果没有,接下来取优先级最高的bean,determineHighestPriorityCandidate方法:

	// determineHighestPriorityCandidate:从给定的Bean里面筛选出一个优先级最高的
	// 什么叫优先级最高呢?主要为了兼容JDK6提供的注解javax.annotation.Priority
	protected String determineHighestPriorityCandidate(Map candidates, Class requiredType) {
		String highestPriorityBeanName = null;
		Integer highestPriority = null;
		for (Map.Entry entry : candidates.entrySet()) {
			String candidateBeanName = entry.getKey();
			Object beanInstance = entry.getValue();
			if (beanInstance != null) {
				//AnnotationAwareOrderComparator#getPriority
				// 这里就是为了兼容JDK6提供的javax.annotation.Priority这个注解,然后做一个优先级排序
				// 注意注意注意:这里并不是@Order,和它木有任何关系
				Integer candidatePriority = getPriority(beanInstance);
				if (candidatePriority != null) {
					if (highestPriorityBeanName != null) {
						// 如果优先级的值相等,是不允许的,这里需要引起注意
						if (candidatePriority.equals(highestPriority)) {
							throw new NoUniqueBeanDefinitionException(requiredType, candidates.size(),
									"Multiple beans found with the same priority ('" + highestPriority +
									"') among candidates: " + candidates.keySet());
						}
						// @Priority设置的value值越小,优先级越高
						else if (candidatePriority < highestPriority) {
							highestPriorityBeanName = candidateBeanName;
							highestPriority = candidatePriority;
						}
					}
					else {
						highestPriorityBeanName = candidateBeanName;
						highestPriority = candidatePriority;
					}
				}
			}
		}
		return highestPriorityBeanName;
	}

如果@Primary和@Priority都没有,最后就要根据beanName来筛选了(相信绝大部分情况下,都会走这里):

Spring源码学习(八)-- 依赖注入源码解析(下)_第6张图片

到这一步就比较简单了,matchesBeanName匹配上Map的key就行。
需要注意的是,bean可能存在很多别名,所以只要有一个别名相同,就认为是能够匹配上的  具体参考AbstractBeanFactory#getAliases方法

如果没有找到,就直接抛错了。
 

以上是根据类型找到多个bean,如果只找到一个,那么就直接拿出来:

else {
	// We have exactly one match.
	Map.Entry entry = matchingBeans.entrySet().iterator().next();
	autowiredBeanName = entry.getKey();
	instanceCandidate = entry.getValue();
}

以上操作拿到了一个符合条件的bean,接下来就是一些处理了:

			// 把找到的autowiredBeanName 放进去
			if (autowiredBeanNames != null) {
				autowiredBeanNames.add(autowiredBeanName);
			}
			// 因为我们需要注入的bean又可能还没有创建,所以可能是BeanClass
			// 底层就是调用了beanFactory.getBean(beanName);  确保该实例肯定已经被实例化了的
			if (instanceCandidate instanceof Class) {
				instanceCandidate = descriptor.resolveCandidate(autowiredBeanName, type, this);
			}
			Object result = instanceCandidate;
			// 如果拿到的bean对象是NullBean,就要判断required
			if (result instanceof NullBean) {
				if (isRequired(descriptor)) {
					raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor);
				}
				result = null;
			}
			// 再一次校验,type和result的type类型是否吻合
			if (!ClassUtils.isAssignableValue(type, result)) {
				throw new BeanNotOfRequiredTypeException(autowiredBeanName, type, instanceCandidate.getClass());
			}
			return result;

以上是DefaultListableBeanFactory中**resolveDependency()方法的分析,流程图:

resolveDependency()流程图

findAutowireCandidates()实现

resolveDependency中有一个方法DefaultListableBeanFactory#findAutowireCandidates:搜索类型匹配的bean的Map,就是根据类型去找bean:

1.找出BeanFactory中类型为type的所有的Bean的名字,注意是名字,而不是Bean对象,因为我们可以根据BeanDefinition就能判断和当前type是不是匹配,不用生成Bean对象

String[] candidateNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
				this, requiredType, true, descriptor.isEager());

 beanNamesForTypeIncludingAncestors:先从本容器找,再从父容器找,最后将结果合并

Spring源码学习(八)-- 依赖注入源码解析(下)_第7张图片

org.springframework.beans.factory.support.DefaultListableBeanFactory#getBeanNamesForType

会调用doGetBeanNamesForType方法,根据类型找beanName,大致流程如下:

Spring源码学习(八)-- 依赖注入源码解析(下)_第8张图片

2.把resolvableDependencies中key为type的对象找出来并添加到result中

// 根据类型从resolvableDependencies中匹配Bean,
// resolvableDependencies中存放的是==类型:Bean对象,比如BeanFactory.class:BeanFactory对象,在Spring启动时设置
for (Map.Entry, Object> classObjectEntry : this.resolvableDependencies.entrySet()) {
	Class autowiringType = classObjectEntry.getKey();
	if (autowiringType.isAssignableFrom(requiredType)) {
		Object autowiringValue = classObjectEntry.getValue();
		autowiringValue = AutowireUtils.resolveAutowiringValue(autowiringValue, requiredType);
		if (requiredType.isInstance(autowiringValue)) {
			result.put(ObjectUtils.identityToString(autowiringValue), autowiringValue);
			break;
		}
	}
}

3.遍历根据type找出的beanName,判断当前beanName对应的Bean是不是能够被自动注入

//不是自引用 && 符合注入条件
// 自引用的判断:找到的候选的Bean的名称和当前Bean名称相等 或者 当前bean名称等于工厂bean的名称
// isAutowireCandidate:这个方法非常的关键,判断该bean是否允许注入进来。泛型的匹配就发生在这个方法里
if (!isSelfReference(beanName, candidate) && isAutowireCandidate(candidate, descriptor)) {
	addCandidateEntry(result, candidate, descriptor, requiredType);
}

 如果不是自己,则调用isAutowireCandidate方法判断该candidate到底能不能用来进行自动注入

org.springframework.beans.factory.support.DefaultListableBeanFactory#isAutowireCandidate:

	@Override
	public boolean isAutowireCandidate(String beanName, DependencyDescriptor descriptor)
			throws NoSuchBeanDefinitionException {
		//getAutowireCandidateResolver()为ContextAnnotationAutowireCandidateResolver
		return isAutowireCandidate(beanName, descriptor, getAutowireCandidateResolver());
	}



	protected boolean isAutowireCandidate(String beanName, DependencyDescriptor descriptor, AutowireCandidateResolver resolver)
			throws NoSuchBeanDefinitionException {

		String beanDefinitionName = BeanFactoryUtils.transformedBeanName(beanName);
		// 若存在Bean定义,就走这里(因为有的Bean可能是直接registerSingleton进来的,是不存在Bean定义的)  
		// 我们的注入,绝大部分情况都走这里
		if (containsBeanDefinition(beanDefinitionName)) {
			//getMergedLocalBeanDefinition方法的作用就是获取缓存的BeanDefinition对象并合并其父类和本身的属性
			return isAutowireCandidate(beanName, getMergedLocalBeanDefinition(beanDefinitionName), descriptor, resolver);
		}
		// 若已经存在实例了,就走这里
		else if (containsSingleton(beanName)) {
			return isAutowireCandidate(beanName, new RootBeanDefinition(getType(beanName)), descriptor, resolver);
		}

		// 父容器  有可能为null,为null就肯定走else默认值了 true 可以注入
		BeanFactory parent = getParentBeanFactory();
		if (parent instanceof DefaultListableBeanFactory) {
			// No bean definition found in this factory -> delegate to parent.
			return ((DefaultListableBeanFactory) parent).isAutowireCandidate(beanName, descriptor, resolver);
		}
		else if (parent instanceof ConfigurableListableBeanFactory) {
			// If no DefaultListableBeanFactory, can't pass the resolver along.
			return ((ConfigurableListableBeanFactory) parent).isAutowireCandidate(beanName, descriptor);
		}
		// 默认值是true
		else {
			return true;
		}
	}


	protected boolean isAutowireCandidate(String beanName, RootBeanDefinition mbd,
			DependencyDescriptor descriptor, AutowireCandidateResolver resolver) {

		String beanDefinitionName = BeanFactoryUtils.transformedBeanName(beanName);
			
		//resolveBeanClass 这个方法之前提到过,主要是保证此Class已经被加载进来了
		resolveBeanClass(mbd, beanDefinitionName);
		//是否已经指定引用非重载方法的工厂方法名。  默认值是true
		if (mbd.isFactoryMethodUnique) {
			boolean resolve;
			synchronized (mbd.constructorArgumentLock) {
				resolve = (mbd.resolvedConstructorOrFactoryMethod == null);
			}
			// 此处主要处理工厂方法的方式,此处先略过~
			if (resolve) {
				new ConstructorResolver(this).resolveFactoryMethodIfPossible(mbd);
			}
		}

		// 核心来了。ContextAnnotationAutowireCandidateResolver#isAutowireCandidate方法
		// 真正的实现在父类:QualifierAnnotationAutowireCandidateResolver它身上
		return resolver.isAutowireCandidate(
				new BeanDefinitionHolder(mbd, beanName, getAliases(beanDefinitionName)), descriptor);
	}

 QualifierAnnotationAutowireCandidateResolver#isAutowireCandidate

	@Override
	public boolean isAutowireCandidate(BeanDefinitionHolder bdHolder, DependencyDescriptor descriptor) {
		// 先执行上层判断,如果匹配成功,在由自己匹配
		boolean match = super.isAutowireCandidate(bdHolder, descriptor);
		if (match) {
			// 拿到descriptor所对应的属性上的所有注解,检查是否有@Qualifier,如果有,看是否和当前bdHolder匹配
			match = checkQualifiers(bdHolder, descriptor.getAnnotations());
			if (match) {
				MethodParameter methodParam = descriptor.getMethodParameter();
				if (methodParam != null) {
					Method method = methodParam.getMethod();
					if (method == null || void.class == method.getReturnType()) {
						// 方法参数前写的@Qualifier
						match = checkQualifiers(bdHolder, methodParam.getMethodAnnotations());
					}
				}
			}
		}
		return match;
	}

首先执行父类的 isAutowireCandidate:

@Override
	public boolean isAutowireCandidate(BeanDefinitionHolder bdHolder, DependencyDescriptor descriptor) {
		if (!super.isAutowireCandidate(bdHolder, descriptor)) {
			// If explicitly false, do not proceed with any other checks...
			return false;
		}
		return checkGenericTypeMatch(bdHolder, descriptor);
	}

依然是先执行父类的 isAutowireCandidate:

	@Override
	public boolean isAutowireCandidate(BeanDefinitionHolder bdHolder, DependencyDescriptor descriptor) {
		return bdHolder.getBeanDefinition().isAutowireCandidate();
	}

先判断beanName对应的BeanDefinition中的autowireCandidate属性(表示是否允许该bena注入到其他bean中,默认为true)

BeanDefinition中的autowireCandidate属性:

Spring源码学习(八)-- 依赖注入源码解析(下)_第9张图片

 如果为false,表示不能用来进行自动注入,如果为true则继续进行判断

判断当前type是不是泛型,如果是泛型是会把容器中所有的beanName找出来的,如果是这种情况,那么在这一步中就要获取到泛型的真正类型,然后进行匹配,如果当前beanName和当前泛型对应的真实类型匹配,那么则继续判断

Spring源码学习(八)-- 依赖注入源码解析(下)_第10张图片

 如果当前DependencyDescriptor上存在@Qualifier注解,那么则要判断当前beanName上是否定义了Qualifier,并且是否和当前DependencyDescriptor上的Qualifier相等,相等则匹配

QualifierAnnotationAutowireCandidateResolver#checkQualifiers:检查@Qualifier注解是否符合条件:@Qualifier可以标注在类上面,也可以达到匹配的效果。(但它不是Bean名称,也不是bean的别名)

	/**
	 * Match the given qualifier annotations against the candidate bean definition.
	 * 将给定的@Qualifier注解与候选bean定义匹配~~~(简单的书就是看看类型已匹配上的,@Qualifier是否还能匹配上)
	 */
	protected boolean checkQualifiers(BeanDefinitionHolder bdHolder, Annotation[] annotationsToSearch) {
		// 这里一般会有两个注解  一个@Autowired 一个@Qualifier  
		// 或者还有其余的组合注解~~~
		if (ObjectUtils.isEmpty(annotationsToSearch)) {
			return true;
		}
		SimpleTypeConverter typeConverter = new SimpleTypeConverter();
		for (Annotation annotation : annotationsToSearch) {
			Class type = annotation.annotationType();
			boolean checkMeta = true;
			boolean fallbackToMeta = false;
			
			//isQualifier:判断是不是@Qualifier注解以及 JSR330的`javax.inject.Qualifier`注解也是支持的
			if (isQualifier(type)) {
				// checkQualifier 最重要的方法就是这个了,它是个重载方法。。。它的内容非常长,大致我在这里解析步骤如下:
				//1、bd.getQualifier 看看Bean定义里是否已经定义过tQualifier们(但是经过我的跟踪,Bean定义得这个字段:private final Map qualifiers;永远不会被赋值 如有人知道,请告知我 了能事Spring预留得吧)
				//2、该Bean定义得AnnotatedElement qualifiedElement的这个属性上是否有指定的注解,有就拿出这个Annotation,否则继续下一步
				//3、resolvedFactoryMethod工厂方法上是否有这个注解,否则进行下一步(下一步事关键。。。)
				//4、Look for matching annotation on the target class  JavaDoc得意思备注也很清晰,就是去具体得类上面,看有没有有对应的注解,有就拿出来。
				//(有个细节):即使这个类被代理了,也是能拿到标注在它上面的注解的  因为: AnnotationUtils.getAnnotation(ClassUtils.getUserClass(bd.getBeanClass()), type)
				//5、到这里,如国获得了对应的@Qualifier注解,那就会比较。如果value值也相同,那就return true,否则继续往下走
				//6、接下来拿到这个注解的attributes,然后判断若@Qualifier没有value值或者是空串,就只return false了  否则继续看
				//7、最终会和Bean上面那个注解(一般都是@Component等注解)的value值和@Qualifier得value值进行比较,若相等  就最终返回true勒(请注意:此处Bean得alias别名若相等也是会返回true)
				//8、======就这样,我们就完成了Bean定义和@Qualifier得一个匹配过程======
				if (!checkQualifier(bdHolder, annotation, typeConverter)) {
					fallbackToMeta = true;
				}
				else {
					checkMeta = false;
				}
			}

			// 这一步非常有效:相当于支持到了组合注解的情况。 它连注解的注解都会解析
			// 比如我们@MyAnno上面还有@Qualifier注解,仍然会被这里解析到的  内部有一个递归
			if (checkMeta) {
				boolean foundMeta = false;
				for (Annotation metaAnn : type.getAnnotations()) {
					Class metaType = metaAnn.annotationType();
					if (isQualifier(metaType)) {
						foundMeta = true;
						// Only accept fallback match if @Qualifier annotation has a value...
						// Otherwise it is just a marker for a custom qualifier annotation.
						if ((fallbackToMeta && StringUtils.isEmpty(AnnotationUtils.getValue(metaAnn))) ||
								!checkQualifier(bdHolder, metaAnn, typeConverter)) {
							return false;
						}
					}
				}
				if (fallbackToMeta && !foundMeta) {
					return false;
				}
			}
		}
		return true;
	}

 经过上述验证之后,当前beanName才能成为一个可注入的,添加到result中

 4.如果筛选后,结果为空,Spring会放宽筛选条件,再筛选一次

Spring源码学习(八)-- 依赖注入源码解析(下)_第11张图片

Spring源码学习(八)-- 依赖注入源码解析(下)_第12张图片

 

关于依赖注入中泛型注入的实现

首先在Java反射中,有一个Type接口,表示类型,具体分类为:

  1. raw types:也就是普通Class
  2. parameterized types:对应ParameterizedType接口,泛型类型
  3. array types:对应GenericArrayType,泛型数组
  4. type variables:对应TypeVariable接口,表示类型变量,也就是所定义的泛型,比如T、K
  5. primitive types:基本类型,int、boolean

大家可以好好看看下面代码所打印的结果:​

public class TypeTest {

	private int i;
	private Integer it;
	private int[] iarray;
	private List list;
	private List slist;
	private List tlist;
	private T t;
	private T[] tarray;

	public static void main(String[] args) throws NoSuchFieldException {

		test(TypeTest.class.getDeclaredField("i"));
		System.out.println("=======");
		test(TypeTest.class.getDeclaredField("it"));
		System.out.println("=======");
		test(TypeTest.class.getDeclaredField("iarray"));
		System.out.println("=======");
		test(TypeTest.class.getDeclaredField("list"));
		System.out.println("=======");
		test(TypeTest.class.getDeclaredField("slist"));
		System.out.println("=======");
		test(TypeTest.class.getDeclaredField("tlist"));
		System.out.println("=======");
		test(TypeTest.class.getDeclaredField("t"));
		System.out.println("=======");
		test(TypeTest.class.getDeclaredField("tarray"));

	}

	public static void test(Field field) {

		if (field.getType().isPrimitive()) {
			System.out.println(field.getName() + "是基本数据类型");
		} else {
			System.out.println(field.getName() + "不是基本数据类型");
		}

		if (field.getGenericType() instanceof ParameterizedType) {
			System.out.println(field.getName() + "是泛型类型");
		} else {
			System.out.println(field.getName() + "不是泛型类型");
		}

		if (field.getType().isArray()) {
			System.out.println(field.getName() + "是普通数组");
		} else {
			System.out.println(field.getName() + "不是普通数组");
		}

		if (field.getGenericType() instanceof GenericArrayType) {
			System.out.println(field.getName() + "是泛型数组");
		} else {
			System.out.println(field.getName() + "不是泛型数组");
		}

		if (field.getGenericType() instanceof TypeVariable) {
			System.out.println(field.getName() + "是泛型变量");
		} else {
			System.out.println(field.getName() + "不是泛型变量");
		}

	}

}

Spring中,但注入点是一个泛型时,也是会进行处理的,比如:​

@Component
public class UserService extends BaseService {

	public void test() {
		System.out.println(o);
	}

}

public class BaseService {

	@Autowired
	protected O o;

	@Autowired
	protected S s;
}

  1. Spring扫描时发现UserService是一个Bean
  2. 那就取出注入点,也就是BaseService中的两个属性o、s
  3. 接下来需要按注入点类型进行注入,但是o和s都是泛型,所以Spring需要确定o和s的具体类型。
  4. 因为当前正在创建的是UserService的Bean,所以可以通过userService.getClass().getGenericSuperclass().getTypeName()获取到具体的泛型信息,比如com.fztx.service.BaseService
  5. 然后再拿到UserService的父类BaseService的泛型变量:for (TypeVariable> typeParameter : userService.getClass().getSuperclass().getTypeParameters()) { System._out_.println(typeParameter.getName()); }
  6. 通过上面两段代码,就能知道,o对应的具体就是OrderService,s对应的具体类型就是StockService
  7. 然后再调用oField.getGenericType()就知道当前field使用的是哪个泛型,就能知道具体类型了

@Qualifier的使用

定义两个注解:

@Target({ElementType.TYPE, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Qualifier("random")
public @interface Random {
}
@Target({ElementType.TYPE, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Qualifier("roundRobin")
public @interface RoundRobin {
}

定义一个接口和两个实现类,表示负载均衡:

public interface LoadBalance {
	String select();
}

@Component
@Random
public class RandomStrategy implements LoadBalance {

	@Override
	public String select() {
		return null;
	}
}
@Component
@RoundRobin
public class RoundRobinStrategy implements LoadBalance {

	@Override
	public String select() {
		return null;
	}
}

使用:

@Component
public class UserService  {

	@Autowired
	@RoundRobin
	private LoadBalance loadBalance;

	public void test() {
		System.out.println(loadBalance);
	}

}

@Resource

@Resource注解的处理是在org.springframework.context.annotation.CommonAnnotationBeanPostProcessor中处理的

和@AutoWired类似,首先是寻找注入点

寻找注入点:

在创建一个Bean的过程中,Spring会利用CommonAnnotationBeanPostProcessor的**postProcessMergedBeanDefinition()**找出注入点并缓存,执行的时间是在实例化完成之后,执行属性赋值之前,会执行BeanDefinition的后置处理(MergedBeanDefinitionPostProcessor)

AutowiredAnnotationBeanPostProcessor.postProcessMergedBeanDefinition

	@Override
	public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class beanType, String beanName) {
		super.postProcessMergedBeanDefinition(beanDefinition, beanType, beanName);
		InjectionMetadata metadata = findResourceMetadata(beanName, beanType, null);
		metadata.checkConfigMembers(beanDefinition);
	}

findResourceMetadata方法中会解析注入点并放入缓存

buildResourceMetadata:

Spring源码学习(八)-- 依赖注入源码解析(下)_第13张图片

 注入点进行注入:
Spring在CommonAnnotationBeanPostProcessor的**postProcessProperties()**方法中,会遍历所找到的注入点依次进行注入。​时间节点在执行完实例化后(InstantiationAwareBeanPostProcessor.postProcessAfterInstantiation)并且在处理完spring自带的依赖注入之后。

CommonAnnotationBeanPostProcessor的postProcessProperties()方法

	@Override
	public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
		InjectionMetadata metadata = findResourceMetadata(beanName, bean.getClass(), pvs);
		try {
			metadata.inject(bean, beanName, pvs);
		}
		catch (Throwable ex) {
			throw new BeanCreationException(beanName, "Injection of resource dependencies failed", ex);
		}
		return pvs;
	}

首先也是去寻找注入点,但是这个时候可以直接从缓存中取到

InjectionMetadata metadata = findResourceMetadata(beanName, bean.getClass(), pvs);


metadata.inject(bean, beanName, pvs)对注入点进行依赖注入:

	public void inject(Object target, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
		Collection checkedElements = this.checkedElements;
		Collection elementsToIterate =
				(checkedElements != null ? checkedElements : this.injectedElements);
		if (!elementsToIterate.isEmpty()) {
			// 遍历每个注入点进行依赖注入
			for (InjectedElement element : elementsToIterate) {
				element.inject(target, beanName, pvs);
			}
		}
	}

遍历每个注入点进行依赖注入,这里我们得到的element对象是InjectedElement的子类ResourceElement,但是ResourceElement没有重写inject方法,所以还是执行的InjectedElement的inject方法:

		protected void inject(Object target, @Nullable String requestingBeanName, @Nullable PropertyValues pvs)
				throws Throwable {

			if (this.isField) {
				Field field = (Field) this.member;
				ReflectionUtils.makeAccessible(field);
				field.set(target, getResourceToInject(target, requestingBeanName));
			}
			else {
				if (checkPropertySkipping(pvs)) {
					return;
				}
				try {
					Method method = (Method) this.member;
					ReflectionUtils.makeAccessible(method);
					method.invoke(target, getResourceToInject(target, requestingBeanName));
				}
				catch (InvocationTargetException ex) {
					throw ex.getTargetException();
				}
			}
		}

getResourceToInject(target, requestingBeanName)方法就是去找具体的bean

在看getResourceToInject方法之前我们先看一下ResourceElement的构造方法:

		public ResourceElement(Member member, AnnotatedElement ae, @Nullable PropertyDescriptor pd) {
			super(member, pd);
			Resource resource = ae.getAnnotation(Resource.class);
			String resourceName = resource.name();
			Class resourceType = resource.type();

			// 使用@Resource时没有指定具体的name,那么则用field的name,或setXxx()中的xxx
			this.isDefaultName = !StringUtils.hasLength(resourceName);
			if (this.isDefaultName) {
				resourceName = this.member.getName();
				if (this.member instanceof Method && resourceName.startsWith("set") && resourceName.length() > 3) {
					resourceName = Introspector.decapitalize(resourceName.substring(3));
				}
			}
			// 使用@Resource时指定了具体的name,进行占位符填充
			else if (embeddedValueResolver != null) {
				resourceName = embeddedValueResolver.resolveStringValue(resourceName);
			}

			// @Resource除开可以指定bean,还可以指定type,type默认为Object
			if (Object.class != resourceType) {
				// 如果指定了type,则验证一下和field的类型或set方法的第一个参数类型,是否和所指定的resourceType匹配
				checkResourceType(resourceType);
			}
			else {
				// No resource type specified... check field/method.
				resourceType = getResourceType();
			}
			this.name = (resourceName != null ? resourceName : "");
			this.lookupType = resourceType;

			String lookupValue = resource.lookup();
			this.mappedName = (StringUtils.hasLength(lookupValue) ? lookupValue : resource.mappedName());

			Lazy lazy = ae.getAnnotation(Lazy.class);
			this.lazyLookup = (lazy != null && lazy.value());
		}

 

首先我们拿到@Resource注解的两个属性,name和type

没有指定具体的name,那么则用field的name,或setXxx()中的xxx,this.isDefaultName会记录我们有没有设置name,如果指定了具体的name,进行占位符填充,得到最后的resourceName,设置给ResourceElement的name属性,

如果指定了type,则验证一下和field的类型或set方法的第一个参数类型,是否和所指定的resourceType匹配,如果没有指定,type就是属性的类型

最后会判断有没有被@Lazy注解标记

接下来看getResourceToInject(target, requestingBeanName)方法:

@Override
		protected Object getResourceToInject(Object target, @Nullable String requestingBeanName) {
			return (this.lazyLookup ? buildLazyResourceProxy(this, requestingBeanName) :
					getResource(this, requestingBeanName));
		}

 如果是@Lazy 注解的注入,则返回的不是具体实例,而是一个代理对象,赋值为该属性。

如果不是,调用getResource(this, requestingBeanName):

 

// 假设@Resource中没有指定name,并且field的name或setXxx()的xxx不存在对应的bean,那么则根据field类型或方法参数类型从BeanFactory去找
if (this.fallbackToDefaultTypeMatch && element.isDefaultName && !factory.containsBean(name)) {
	autowiredBeanNames = new LinkedHashSet<>();
	resource = beanFactory.resolveDependency(descriptor, requestingBeanName, autowiredBeanNames, null);
	if (resource == null) {
		throw new NoSuchBeanDefinitionException(element.getLookupType(), "No resolvable resource object");
	}
}
else {
	resource = beanFactory.resolveBeanByName(name, descriptor);
	autowiredBeanNames = Collections.singleton(name);
}

this.fallbackToDefaultTypeMatch:可以理解为要不要根据类型去找bean,默认是true

element.isDefaultName:@Resource中有没有指定name,没有指定为true

factory.containsBean(name):判断bean工厂中是否包含该name的bean

假设@Resource没有指定name,并且field的name或setXxx()的xxx(默认name)不存在对应的bean,那么则根据field类型或方法参数类型从BeanFactory去找

resource = beanFactory.resolveDependency(descriptor, requestingBeanName, autowiredBeanNames, null);

这个方法就是上面一开始分析的方法,根据类型去匹配得到bean

假设@Resource没有指定name,但是field的name或setXxx()的xxx(默认name)在bean工厂中存在对应的bean;或者@Resource指定了name,那么就直接根据name去getBean

else {
	resource = beanFactory.resolveBeanByName(name, descriptor);
	autowiredBeanNames = Collections.singleton(name);
}

 resolveBeanByName:

Spring源码学习(八)-- 依赖注入源码解析(下)_第14张图片

 

@Resource注解底层工作流程图:

Spring源码学习(八)-- 依赖注入源码解析(下)_第15张图片

@Resource装配顺序
  1. 如果同时指定了name和type,则从Spring上下文中找到唯一匹配的bean进行装配,找不到则抛出异常
  2. 如果指定了name,则从上下文中查找名称(id)匹配的bean进行装配,找不到则抛出异常
  3. 如果指定了type,则从上下文中找到类型匹配的唯一bean进行装配,找不到或者找到多个,都会抛出异常
  4. 如果既没有指定name,又没有指定type,则自动按照byName方式进行装配;如果没有匹配,则回退为一个原始类型进行匹配,如果匹配则自动装配;

你可能感兴趣的:(Spring源码,spring,java,源码)