前言
前面我发布了Spring IOC容器的刷新(初始化)过程,以及Spring 容器的Bean的实例化、初始化过程。其中有一个步骤小伙伴们比较关心,也提问的比较多,那就是泛型依赖注入。鉴于之前对这一块描述得也不是很详细,鉴于此处还是比较重要的,因此本文专门用篇幅聊聊这个事
看本篇文章之前,建议至少已经了解Spring容器的一个大致过程,最好已经看过博文(或者知道):
【小家Spring】AbstractAutowireCapableBeanFactory#populateBean实现Bean的属性赋值和initializeBean对Bean的初始化
因此本文将直接从依赖注入这一步,分析Spring是怎么样实现控制反转、依赖注入(DI)的~
Demo Show(自动装配的)
在讲解之前,先构造一个例子看看效果(效果很像RedisTemplate):
// 准备一个带泛型的Bean @Getter @Setter @NoArgsConstructor @AllArgsConstructor @ToString public class GenericBean<T, W> { private T t; private W w; } // config配置文件中注入两个泛型Bean @Bean public Parent parentOne() { return new Parent(); } @Bean public Parent parentTwo() { return new Parent(); } @Bean public GenericBean<String, String> stringGeneric() { return new GenericBean<String, String>("str1", "str2"); } @Bean public GenericBean<Object, Object> objectGeneric() { return new GenericBean<Object, Object>("obj1", 2); } // 使用@Autowired注入,测试一下: @Autowired private GenericBean<Object, Object> objectGenericBean; //GenericBean(t=obj1, w=2) @Autowired private GenericBean<String, String> stringGenericBean; //GenericBean(t=st r1, w=str2) // 注意,容器里虽然有两个Parent,这里即使不使用@Qualifier也不会报错。 // 但是需要注意字段名parentOne,必须是容器里存在的,否则就报错了。 @Autowired private Parent parentOne; //com.fsx.bean.Parent@23c98163 //Spring4.0后的新特性,这样会注入所有类型为(包括子类)GenericBean的Bean(但是顺序是不确定的,可通过Order接口控制顺序) @Autowired private List<GenericBean> genericBeans; //[GenericBean(t=st r1, w=str2), GenericBean(t=obj1, w=2)] // 这里的key必须是String类型,把GenericBean类型的都拿出来了,beanName->Bean @Autowired private Map<String, GenericBean> genericBeanMap; //{stringGenericBean=GenericBean(t=st r1, w=str2), objectGenericBean=GenericBean(t=obj1, w=2)} // 这里面,用上泛型也是好使的,就只会拿指定泛型的了 @Autowired private Map<String, GenericBean<Object, Object>> genericBeanObjMap; //{objectGenericBean=GenericBean(t=obj1, w=2)} // 普通类型,容器里面没有的Bean类型,注入是会报错的 //@Autowired //private Integer normerValue;
如果你还不知道泛型依赖注入的话,就应该有这样一个疑问(应该有哈,若没有,看来你对@Autowired还没有个概性的认识):
@Autowired明明是根据类型进行注入的,那我们往容器里放置了两个GenericBean类型的Bean,为何启动没有报错呢???
(最直观的感受:若我们的service有两个serviceImpl,直接仅使用@Autowired注入是会报错的)
那么接下来,我们通过跟踪源码的方式,一层一层剥开内部的缘由,看看葫芦里到底是什么药~
依赖注入源码分析
在上面推荐的博文里已经讲到了,Spring在populateBean这一步为属性赋值的时候,会执行InstantiationAwareBeanPostProcessor处理器的postProcessPropertyValues方法。
这里AutowiredAnnotationBeanPostProcessor该处理器的postProcessPropertyValues方法就是来处理该注解的。(因此,我们的源码解析从此处开始吧~~~~)
@Override public PropertyValues postProcessPropertyValues( PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeanCreationException { // 找到所有的@Autowired元数据-------当前值可以见下图 InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs); try { // 所以我们看InjectionMetadata 的inject即可,见下 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; }
metadata值如下:
InjectionMetadata#inject
:
public void inject(Object target, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable { Collection<InjectedElement> checkedElements = this.checkedElements; // 这里是待遍历、待处理的属性Element们(备注,本处的InjectedElement实现类为:AutowiredFieldElement 因为我们是Field注入嘛) // 所以从下可知,我们直接看AutowiredFieldElement#inject方法吧 Collection<InjectedElement> elementsToIterate = (checkedElements != null ? 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); } } }
AutowiredFieldElement#inject
:根据字段注入
AutowiredFieldElement是AutowiredAnnotationBeanPostProcessor的一个私有普
通内部类,高内聚~
// 这段代码虽然长,其实核心逻辑还并不在这里,而是在beanFactory Bean工厂的resolveDependency处理依赖实现里 @Override 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 { // 把field和required属性,包装成desc描述类 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 { // 把desc传进去,里面还有注解信息、元信息等等,这个方法是根据注解信息寻找到依赖的Bean的核心逻辑 // 备注:此部分处理依赖逻辑交给Bean工厂,其实也没毛病。毕竟它处理的相当于是Field // 那么接下里,重点分析resolveDependency这个方法 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) && 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); } } }
DefaultListableBeanFactory#resolveDependency
:解决依赖(根据依赖关系找到值)
@Override @Nullable public Object resolveDependency(DependencyDescriptor descriptor, @Nullable String requestingBeanName, @Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException { // 把当前Bean工厂的名字发现器赋值给传进来DependencyDescriptor 类 // 这里面注意了:有必要说说名字发现器这个东西,具体看下面吧==========还是比较重要的 // Bean工厂的默认值为:private ParameterNameDiscoverer parameterNameDiscoverer = new DefaultParameterNameDiscoverer(); descriptor.initParameterNameDiscovery(getParameterNameDiscoverer()); // 支持到Optional类型的注入,比如我们这样注入:private Optional<GenericBean<Object, Object>> objectGenericBean; // 也是能够注入进来的,只是类型变为,Optional[GenericBean(t=obj1, w=2)] // 对于Java8中Optional类的处理 if (Optional.class == descriptor.getDependencyType()) { return createOptionalDependency(descriptor, requestingBeanName); } // 兼容ObjectFactory和ObjectProvider(Spring4.3提供的接口) // 关于ObjectFactory和ObjectProvider在依赖注入中的大作用,我觉得是非常有必要再撰文讲解的 //对于前面讲到的提早曝光的ObjectFactory的特殊处理 else if (ObjectFactory.class == descriptor.getDependencyType() || ObjectProvider.class == descriptor.getDependencyType()) { return new DependencyObjectProvider(descriptor, requestingBeanName); } // 支持到了javax.inject.Provider这个类的实现 else if (javaxInjectProviderClass == descriptor.getDependencyType()) { return new Jsr330ProviderFactory().createDependencyProvider(descriptor, requestingBeanName); } // 这个应该是我们觉得部分触及到的,其实不管何种方式,最终都是交给doResolveDependency方法去处理了 else { //getAutowireCandidateResolver()得到ContextAnnotationAutowireCandidateResolver 根据依赖注解信息,找到对应的Bean值信息 //getLazyResolutionProxyIfNecessary方法,它也是唯一实现。 //如果字段上带有@Lazy注解,表示进行懒加载 Spring不会立即创建注入属性的实例,而是生成代理对象,来代替实例 Object result = getAutowireCandidateResolver().getLazyResolutionProxyIfNecessary( descriptor, requestingBeanName); // 如果在@Autowired上面还有个注解@Lazy,那就是懒加载的,是另外一种处理方式(是一门学问) // 这里如果不是懒加载的(绝大部分情况都走这里) 就进入核心方法doResolveDependency 下面有分解 if (result == null) { result = doResolveDependency(descriptor, requestingBeanName, autowiredBeanNames, typeConverter); } return result; } }
DefaultListableBeanFactory#doResolveDependency
处理属性依赖关系的核心方法:通用的处理逻辑
@Nullable public Object doResolveDependency(DependencyDescriptor descriptor, @Nullable String beanName, @Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException { // 相当于打个点,记录下当前的步骤位置 返回值为当前的InjectionPoint InjectionPoint previousInjectionPoint = ConstructorResolver.setCurrentInjectionPoint(descriptor); try { // 简单的说就是去Bean工厂的缓存里去看看,有没有名称为此的Bean,有就直接返回,没必要继续往下走了 // 比如此处的beanName为:objectGenericBean等等 Object shortcut = descriptor.resolveShortcut(this); if (shortcut != null) { return shortcut; } // 此处为:class com.fsx.bean.GenericBean Class<?> type = descriptor.getDependencyType(); // 看看ContextAnnotationAutowireCandidateResolver的getSuggestedValue方法,具体实现在父类 QualifierAnnotationAutowireCandidateResolver中 //处理@Value注解------------------------------------- //获取@Value中的value属性 Object value = getAutowireCandidateResolver().getSuggestedValue(descriptor); // 若存在value值,那就去解析它。使用到了AbstractBeanFactory#resolveEmbeddedValue // 也就是使用StringValueResolver处理器去处理一些表达式~~ 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())); } //对数组、Collection、Map等类型进行处理,也是支持自动注入的。 //因为是数组或容器,Sprng可以直接把符合类型的bean都注入到数组或容器中,处理逻辑是: //1.确定容器或数组的组件类型 if else 分别对待,分别处理 //2.调用findAutowireCandidates(核心方法)方法,获取与组件类型匹配的Map(beanName -> bean实例) //3.将符合beanNames添加到autowiredBeanNames中 Object multipleBeans = resolveMultipleBeans(descriptor, beanName, autowiredBeanNames, typeConverter); if (multipleBeans != null) { return multipleBeans; } // 获取所有【类型】匹配的Beans,形成一个Map(此处用Map装,是因为可能不止一个符合条件) // 该方法就特别重要了,对泛型类型的匹配、对@Qualifierd的解析都在这里面,下面详情分解 Map<String, Object> matchingBeans = findAutowireCandidates(beanName, type, descriptor); // 若没有符合条件的Bean。。。 if (matchingBeans.isEmpty()) { // 并且是必须的,那就抛出没有找到合适的Bean的异常吧 // 我们非常熟悉的异常信息:expected at least 1 bean which qualifies as autowire candidate... if (isRequired(descriptor)) { raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor); } return null; } String autowiredBeanName; Object instanceCandidate; //如果类型匹配的bean不止一个,Spring需要进行筛选,筛选失败的话继续抛出异常 // 如果只找到一个该类型的,就不用进这里面来帮忙筛选了~~~~~~~~~ if (matchingBeans.size() > 1) { // 该方法作用:从给定的beans里面筛选出一个符合条件的bean,此筛选步骤还是比较重要的,因此看看可以看看下文解释吧 autowiredBeanName = determineAutowireCandidate(matchingBeans, descriptor); if (autowiredBeanName == null) { // 如果此Bean是要求的,或者 不是Array、Collection、Map等类型,那就抛出异常NoUniqueBeanDefinitionException if (isRequired(descriptor) || !indicatesMultipleBeans(type)) { // 抛出此异常 return descriptor.resolveNotUnique(type, matchingBeans); } // Spring4.3之后才有:表示如果是required=false,或者就是List Map类型之类的,即使没有找到Bean,也让它不抱错,因为最多注入的是空集合嘛 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. // 仅仅只匹配上一个,走这里 很简单 直接拿出来即可 // 注意这里直接拿出来的技巧:不用遍历,直接用iterator.next()即可 Map.Entry<String, Object> entry = matchingBeans.entrySet().iterator().next(); autowiredBeanName = entry.getKey(); instanceCandidate = entry.getValue(); } // 把找到的autowiredBeanName 放进去 if (autowiredBeanNames != null) { autowiredBeanNames.add(autowiredBeanName); } // 底层就是调用了beanFactory.getBean(beanName); 确保该实例肯定已经被实例化了的 if (instanceCandidate instanceof Class) { instanceCandidate = descriptor.resolveCandidate(autowiredBeanName, type, this); } Object result = instanceCandidate; 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; } // 最终把节点归还回来 finally { ConstructorResolver.setCurrentInjectionPoint(previousInjectionPoint); } }
若出现多个Bean,将由下面方法去匹配和决定~
//determineAutowireCandidate 从多个Bean中,筛选出一个符合条件的Bean @Nullable protected String determineAutowireCandidate(Map<String, Object> candidates, DependencyDescriptor descriptor) { Class<?> requiredType = descriptor.getDependencyType(); // 看看传入的Bean中有没有标注了@Primary注解的 String primaryCandidate = determinePrimaryCandidate(candidates, requiredType); // 如果找到了 就直接返回 // 由此可见,@Primary的优先级还是非常的高的 if (primaryCandidate != null) { return primaryCandidate; } //找到一个标注了javax.annotation.Priority注解的。(备注:优先级的值不能有相同的,否则报错) String priorityCandidate = determineHighestPriorityCandidate(candidates, requiredType); if (priorityCandidate != null) { return priorityCandidate; } // Fallback // 这里是最终的处理(相信绝大部分情况下,都会走这里~~~~~~~~~~~~~~~~~~~~) // 此处就能看出resolvableDependencies它的效能了,他会把解析过的依赖们缓存起来,不用再重复解析了 for (Map.Entry<String, Object> entry : candidates.entrySet()) { String candidateName = entry.getKey(); Object beanInstance = entry.getValue(); // 到这一步就比较简单了,matchesBeanName匹配上Map的key就行。 // 需要注意的是,bean可能存在很多别名,所以只要有一个别名相同,就认为是能够匹配上的 具体参考AbstractBeanFactory#getAliases方法 //descriptor.getDependencyName() 这个特别需要注意的是:如果是字段,这里调用的this.field.getName() 直接用的是字段的名称 // 因此此处我们看到的情况是,我们采用@Autowired虽然匹配到两个类型的Bean了,即使我们没有使用@Qualifier注解,也会根据字段名找到一个合适的(若没找到,就抱错了) if ((beanInstance != null && this.resolvableDependencies.containsValue(beanInstance)) || matchesBeanName(candidateName, descriptor.getDependencyName())) { return candidateName; } } return null; } //determinePrimaryCandidate:顾名思义。它是从给定的Bean中看有木有标注了@Primary注解的Bean,有限选择它 @Nullable protected String determinePrimaryCandidate(Map<String, Object> candidates, Class<?> requiredType) { String primaryBeanName = null; for (Map.Entry<String, Object> 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; } // determineHighestPriorityCandidate:从给定的Bean里面筛选出一个优先级最高的 // 什么叫优先级最高呢?主要为了兼容JDK6提供的注解javax.annotation.Priority @Nullable protected String determineHighestPriorityCandidate(Map<String, Object> candidates, Class<?> requiredType) { String highestPriorityBeanName = null; Integer highestPriority = null; for (Map.Entry<String, Object> entry : candida tes.entrySet()) { String candidateBeanName = entry.getKey(); Object beanInstance = entry.getValue(); if (beanInstance != null) { //AnnotationAwareOrderComparator#getPriority // 这里就是为了兼容JDK6提供的javax.annotation.Priority这个注解,然后做一个优先级排序 // 注意注意注意:这里并不是@Order,和它木有任何关系~~~ // 它有的作用像Spring提供的@Primary注解 Integer candidatePriority = getPriority(beanInstance); // 大部分情况下,我们这里都是null,但是需要注意的是,@Primary只能标注一个,这个虽然可以标注多个,但是里面的优先级值,不能出现相同的(强烈建议不要使用~~~~而使用@Primary) if (candidatePriority != null) { if (highestPriorityBeanName != null) { // 如果优先级的值相等,是不允许的,这里需要引起注意,个人建议一般还是使用@Primary吧 if (candidatePriority.equals(highestPriority)) { throw new NoUniqueBeanDefinitionException(requiredType, candidates.size(), "Multiple beans found with the same priority ('" + highestPriority + "') among candidates: " + candidates.keySet()); } else if (candidatePriority < highestPriority) { highestPriorityBeanName = candidateBeanName; highestPriority = candidatePriority; } } else { highestPriorityBeanName = candidateBeanName; highestPriority = candidatePriority; } } } } return highestPriorityBeanName; }