上篇文章分析了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方法:
如果是@Lazy
注解的注入,则返回的不是具体实例,而是一个代理对象,赋值为该属性。
如果是普通的@Autowired
注解 ,则会调用 doResolveDependency
方法。
如果当前descriptor之前做过依赖注入了,则可以直接取shortcut了,相当于缓存,简单的说就是去Bean工厂的缓存里去看看,有没有名称为此的Bean,有就直接返回,没必要继续往下走了
Object value = getAutowireCandidateResolver().getSuggestedValue(descriptor);
@value注解的处理:
getAutowireCandidateResolver()得到ContextAnnotationAutowireCandidateResolver,getSuggestedValue方法,具体实现在父类 QualifierAnnotationAutowireCandidateResolver中:
判断注入的字段或者方法参数有没有@Value注解,有的话拿到@Value注解的value,没有则返回null
拿到@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的解析都在这里面,下面详情分解
如果没有符合条件的bean,并且required为true,抛出异常
如果根据类型找到了多个Bean,进一步筛选出某一个
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来筛选了(相信绝大部分情况下,都会走这里):
到这一步就比较简单了,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()流程图
resolveDependency中有一个方法DefaultListableBeanFactory#findAutowireCandidates
:搜索类型匹配的bean的Map,就是根据类型去找bean:
1.找出BeanFactory中类型为type的所有的Bean的名字,注意是名字,而不是Bean对象,因为我们可以根据BeanDefinition就能判断和当前type是不是匹配,不用生成Bean对象
String[] candidateNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
this, requiredType, true, descriptor.isEager());
beanNamesForTypeIncludingAncestors:先从本容器找,再从父容器找,最后将结果合并
org.springframework.beans.factory.support.DefaultListableBeanFactory#getBeanNamesForType
会调用doGetBeanNamesForType方法,根据类型找beanName,大致流程如下:
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属性:
如果为false,表示不能用来进行自动注入,如果为true则继续进行判断
判断当前type是不是泛型,如果是泛型是会把容器中所有的beanName找出来的,如果是这种情况,那么在这一步中就要获取到泛型的真正类型,然后进行匹配,如果当前beanName和当前泛型对应的真实类型匹配,那么则继续判断
如果当前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会放宽筛选条件,再筛选一次
首先在Java反射中,有一个Type接口,表示类型,具体分类为:
大家可以好好看看下面代码所打印的结果:
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;
}
userService.getClass().getGenericSuperclass().getTypeName()
获取到具体的泛型信息,比如com.fztx.service.BaseService
for (TypeVariable> typeParameter : userService.getClass().getSuperclass().getTypeParameters()) { System._out_.println(typeParameter.getName()); }
oField.getGenericType()
就知道当前field使用的是哪个泛型,就能知道具体类型了定义两个注解:
@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注解的处理是在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在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:
@Resource注解底层工作流程图:
@Resource装配顺序
1. 如果同时指定了name和type,则从Spring上下文中找到唯一匹配的bean进行装配,找不到则抛出异常
2. 如果指定了name,则从上下文中查找名称(id)匹配的bean进行装配,找不到则抛出异常
3. 如果指定了type,则从上下文中找到类型匹配的唯一bean进行装配,找不到或者找到多个,都会抛出异常
4. 如果既没有指定name,又没有指定type,则自动按照byName方式进行装配;如果没有匹配,则回退为一个原始类型进行匹配,如果匹配则自动装配;