AutowiredFieldElement实现属性依赖注入
这个类继承自静态抽象内部类InjectionMetadata.InjectedElement,并且它还是AutowiredAnnotationBeanPostProcessor的private内部类,体现出非常高的内聚性:
// 它的宿主类是AutowiredAnnotationBeanPostProcessor 高内聚低耦合 private class AutowiredFieldElement extends InjectionMetadata.InjectedElement { private final boolean required; private volatile boolean cached = false; @Nullable private volatile Object cachedFieldValue; //唯一构造方法 public AutowiredFieldElement(Field field, boolean required) { super(field, null); // 此处显示调用父类的构造函数 this.required = required; } // 核心方法:字段的依赖注入 @Override protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable { // 显然此处父类的member就指的是filed Field field = (Field) this.member; Object value; // 走缓存,关于cachedFieldValue的值 且听下文分解 if (this.cached) { value = resolvedCachedArgument(beanName, this.cachedFieldValue); } else { // 每个Field都包装成一个DependencyDescriptor // 如果是Method包装成DependencyDescriptor,毕竟一个方法可以有多个入参 // 此处包装成它后,显然和元数据都无关了,只和Field有关了 完全隔离 DependencyDescriptor desc = new DependencyDescriptor(field, this.required); desc.setContainingClass(bean.getClass()); Set<String> autowiredBeanNames = new LinkedHashSet<>(1); Assert.state(beanFactory != null, "No BeanFactory available"); // 转换器使用的bean工厂的转换器~~~ TypeConverter typeConverter = beanFactory.getTypeConverter(); try { // 获取依赖的value值的工作 最终还是委托给beanFactory.resolveDependency()去完成的~~~~ // 这个接口方法由AutowireCapableBeanFactory提供,它提供了从bean工厂里获取依赖值的能力~ value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter); } catch (BeansException ex) { throw new UnsatisfiedDependencyException(null, beanName, new InjectionPoint(field), ex); } // 下面代码是把缓存值缓存起来 让同一个Field注入多次能提高效率 synchronized (this) { if (!this.cached) { // 可以看到value!=null并且required=true才会进行缓存的处理 // 按照上例 此处value值为A@2277实例 if (value != null || this.required) { this.cachedFieldValue = desc; // 可以看到缓存的值是上面的DependencyDescriptor对象~~~~ // 这个方法是宿主类AutowiredAnnotationBeanPostProcessor的方法 // 简单的说就是注册到bean工厂去,比如此处b是依赖a的 所以就注册这个依赖关系进去了 // 参考this.beanFactory.registerDependentBean(autowiredBeanName, beanName); registerDependentBeans(beanName, autowiredBeanNames); // autowiredBeanNames里可能会有别名的名称~~~所以size可能大于1 if (autowiredBeanNames.size() == 1) { // beanFactory.isTypeMatch挺重要的~~~~因为@Autowired是按照类型注入的 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; } } } // 不为null,就完成最终的set值 利用反射给filed属性赋值~~~~ if (value != null) { ReflectionUtils.makeAccessible(field); field.set(bean, value); } } }
前面准备好的注解的
、需要注入的元数据信息,这一步使用执行注入。
从源码中也能发现一个特点,Spring大量的使用到了转换、适配、委托等机制。因此最终最最最重要的一行代码无非是这一句:
value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);
委托AutowireCapableBeanFactory来获取到依赖值value,从而最终完成注入(反射执行注入~)。
so,其实最核心还是在Bean工厂里,也就是它的唯一内建实现类DefaultListableBeanFactory
DefaultListableBeanFactory解析依赖值
分离关注,本处只看它解析依赖值的方法resolveDependency():
public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory implements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable { ... @Override @Nullable public Object resolveDependency(DependencyDescriptor descriptor, @Nullable String requestingBeanName, @Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException { //此处使用的是DefaultParameterNameDiscoverer 来获取参数名 // 这就是为什么我们使用@Autowired注入,即使有多个同类型的Bean,也可以通过field属性名进行区分的根本原因(可以不需要使用@Qualifier注解) descriptor.initParameterNameDiscovery(getParameterNameDiscoverer()); // 支持Optional 原来还是doResolveDependency 暂略 if (Optional.class == descriptor.getDependencyType()) { return createOptionalDependency(descriptor, requestingBeanName); } // 原理也是doResolveDependency 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); } else { // 绝大部分情况下 肯定走到这里~~~~ // 此处特别特别的需要重视:这是@Lazy支持的根本原因~~ // 关于AutowireCandidateResolver我建议小伙伴先看下一个章节~~~ // 此处若通过AutowireCandidateResolver解析到了值就直接返回了(若标注了@Lazy,此处的result将不会为null了~~~) Object result = getAutowireCandidateResolver().getLazyResolutionProxyIfNecessary(descriptor, requestingBeanName); // doResolveDependency是绝大多数情况下 最终会去执行的代码(若result仍旧为null的话) if (result == null) { result = doResolveDependency(descriptor, requestingBeanName, autowiredBeanNames, typeConverter); } return result; } } ... }
截止到这,整个流程中有两句非常重要的代码不容忽视:
第一句是:
/
Object result = getAutowireCandidateResolver().getLazyResolutionProxyIfNecessary(descriptor, requestingBeanName)
它会解析@Lazy这个注解,来创建代理对象。而如果它已经创建了,就不会执行第二句了。
关于这句代码的详细解释、分析,请参阅(强烈建议阅读一下本文):
【小家Spring】Spring依赖注入(DI)核心接口AutowireCandidateResolver深度分析,解析@Lazy、@Qualifier注解的原理
第二句:(重中之重)
绝大多数情况下,肯定会经由我们的doResolveDependency()方法来处理,因此这个方法的实现才是重中之重。
看过上文你就能知道:其实getLazyResolutionProxyIfNecessary()它的底层依赖还是doResolveDependency()这个方法
看看DefaultListableBeanFactory对这个"重中之重"的实现:
// 此处autowiredBeanNames是在inject的一个空的Set // autowired表示最终可以注入进去的bean名称们(因为可能是会有多个符合条件的) public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory implements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable { ... @Nullable public Object doResolveDependency(DependencyDescriptor descriptor, @Nullable String beanName, @Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException { // 记录注入点,其实使用的ThreadLocal~ InjectionPoint previousInjectionPoint = ConstructorResolver.setCurrentInjectionPoint(descriptor); try { // 只有ShortcutDependencyDescriptor实现了resolveShortcut方法,其实就是根据 // 实现也就一句话:beanFactory.getBean(this.shortcut, this.requiredType) // ShortcutDependencyDescriptor实在inject完成后创建的,就是有缓存的效果~~~ Object shortcut = descriptor.resolveShortcut(this); if (shortcut != null) { return shortcut; } // interface com.fsx.dependency.AInterface Class<?> type = descriptor.getDependencyType(); // 拿到@Value注解的value值(是个字符串) 若没有标注@Value 显然就不用那啥了 // 从此处其实也可以看出,@Value注解的优先级对于找到bean来说还是蛮高的 Object value = getAutowireCandidateResolver().getSuggestedValue(descriptor); // ============ 这部分主要是解析@Value注解 // 解析它的占位符,解析它的SpEL表达式 // 相关处理类曹靠BeanExpressionResolver和StandardBeanExpressionResolver StandardEvaluationContext等 // 因为关于@Value的文章里详细解过,此处一笔带过~~~ 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())); } } // ============ // 此处处理的是多值注入的情况,比如注入Stream<Object>、Map、Array、Collection等等 Spring都是支持的 // 需要稍微注意一点,Stream这种类型的注入在Spring4以上才得到支持的 Object multipleBeans = resolveMultipleBeans(descriptor, beanName, autowiredBeanNames, typeConverter); if (multipleBeans != null) { return multipleBeans; } // 显然绝大部分情况下,都会走到这里(因为大部分我们都是单值注入~) // findAutowireCandidates可以说又是整个依赖注入的灵魂之一~~~~ 它的查找步骤简述如下: //1、BeanFactoryUtils.beanNamesForTypeIncludingAncestors() 找到这种类型的所有的beanNames(candidateNames)(可能有多个哟,但大多数情况下只有一个) //2、处理resolvableDependencies比如ApplicationContext的依赖,让他们也能够正常注入进去(他们可不作为bean存在容器里~) //3、遍历candidateNames:检查它是否可以被依赖、容器内是否存在bean定义(或者Singleton) 若符合,getBean()出来放在map里 //4、若返回的Map不为Empty()了,直接return 表示找到了(当然还可能是多个~~) // 若返回的还是Empty,那就继续检查requiredType是否为Map、Collection等类型,从它里面去找。。。(这种注入case使用太少,此处暂略~) Map<String, Object> matchingBeans = findAutowireCandidates(beanName, type, descriptor); // 所以matchingBeans证明没有找到匹配的,但requied=true,所以此处就抛出异常了~ if (matchingBeans.isEmpty()) { if (isRequired(descriptor)) { raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor); } return null; } String autowiredBeanName; Object instanceCandidate; // 若有多个匹配 // 需要注意的是:@Qualifier注解在上面就已经生效了~~~~因为AutowireCandidateResolver.isAutowireCandidate是在上面生效的 if (matchingBeans.size() > 1) { // 由它进行判别 从弱水三千中 取出一瓢 // 1、是否标注有@Primary 有这种bean就直接返回(@Primary只允许标注在一个同类型Bean上) // 2、看是否有标注有`javax.annotation.Priority`这个注解的 // 3、根据字段field名,去和beanName匹配 匹配上了也行(这就是为何我们有时候不用@Qulifier也没事的原因之一) // 此处注意:descriptor.getDependencyName()这个属性表示字段名,靠的是`DefaultParameterNameDiscoverer`去把字段名取出来的~ autowiredBeanName = determineAutowireCandidate(matchingBeans, descriptor); if (autowiredBeanName == null) { if (isRequired(descriptor) || !indicatesMultipleBeans(type)) { // 此处抛出异常:NoUniqueBeanDefinitionException 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) { // 此处getBean() 拿到该类型的实例对象了~~~ 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); } } ... }