spring里【集合类型属性】的注入

关键字:

  1. spring
  2. 集合类型属性赋值
  3. List类型属性注入
  4. spring源码
  5. getBeanNamesByType
  6. AUTOWIRE_BY_TYPE
如何为集合类型的属性注入内容
  1. 定义了一个接口IOrderAlipayStrategy
public interface IOrderAlipayStrategy { PayType getPayType(); OrderInfo payThroughAlipay(AlipayConfig alipayConfig,PayType payType, String orderId, String alipayUserId) throws Exception; }

  1. 新建一箩筐类,这些类都实现IOrderAlipayStrategy接口
@Component public class ActivityOrderStrategy extends AbstractOrderAlipayStrategy { /** 省略内部代码 */ }@Component public class OrgOrderObjStrategy extends AbstractOrderAlipayStrategy { /** 省略内部代码 */ }// // 省略项目里其它的实现类 //

  1. 在代码里注入集合属性
@Component public class OrderStrategyFactory {// 用这个list来装载所有的策略类 @Autowired private List orderStrategyList; // 省略其它代码}

【spring里【集合类型属性】的注入】上面的代码里通过@Autowired注解的orderStrategyList,将会被实现了范型接口IOrderAlipayStrategy的非抽象类的实例填充。
这样就很容易的为orderStrategyList赋值了,他的内容就是系统里实现了IOrderAlipayStrategy接口的实现类的对象实例。
运行截图如下:
spring里【集合类型属性】的注入
文章图片
被注入的集合类型属性
  1. 恭喜各位,大功告成!不想了解原理的可以撤了 _
通过源码了解一下spring如何给集合类型赋值的
  1. spring环境在初始化的过程中,doCreateBean阶段,会调用populateBean(beanName, mbd, instanceWrapper); 方法为正在实例化的bean的属性赋值。
  2. populateBean(beanName, mbd, instanceWrapper); 方法中,会调用后置处理器,代码如下:
for (BeanPostProcessor bp : getBeanPostProcessors()) { if (bp instanceof InstantiationAwareBeanPostProcessor) { InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp; /* 注释:这里完成属性注入,包括循环依赖*/ PropertyValues pvsToUse = ibp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName); if (pvsToUse == null) { if (filteredPds == null) { filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching); } pvsToUse = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName); if (pvsToUse == null) { return; } } pvs = pvsToUse; } } }

上述代码中的for循环getBeanPostProcessors()方法返回的众多beanPostProcessor们,当遍历到AutowiredAnnotationBeanPostProcessor时调用postProcessProperties(pvs, bw.getWrappedInstance(), beanName); 会处理与@Autowired属性注入相关的逻辑。请看下面断点截图

spring里【集合类型属性】的注入
文章图片
@Autowired注解的处理过程
AutowiredAnnotationBeanPostProcessor里,几经周折会进入protected void inject( ... )方法,代码如下:
@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 = https://www.it610.com/article/resolvedCachedArgument(beanName, this.cachedFieldValue); } else { DependencyDescriptor desc = new DependencyDescriptor(field, this.required); desc.setContainingClass(bean.getClass()); Set autowiredBeanNames = new LinkedHashSet<>(1); Assert.state(beanFactory != null, "No BeanFactory available"); TypeConverter typeConverter = beanFactory.getTypeConverter(); try { // 重要:这里在依赖注入时,解决依赖关系 value = https://www.it610.com/article/beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter); } catch (BeansException ex) { throw new UnsatisfiedDependencyException(null, beanName, new InjectionPoint(field), ex); } ... 后面代码不贴出来了 ... } }

请注意上面源码try{}里面的value = https://www.it610.com/article/beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter); 部分,从这里再次劈荆斩棘,最终会来到DefaultListableBeanFactoryprivate Object resolveMultipleBeans( ... )方法,这是个很重要的方法,这个方法的名字很直观:处理多个Beans,还是复数。该方法里会根据属性的类型,来决定如何填充该属性,下面截取一小段与集合类型有关的代码
else if (Collection.class.isAssignableFrom(type) && type.isInterface()) { Class elementType = descriptor.getResolvableType().asCollection().resolveGeneric(); if (elementType == null) { return null; } // 找到候选者 Map matchingBeans = findAutowireCandidates(beanName, elementType, new MultiElementDescriptor(descriptor)); if (matchingBeans.isEmpty()) { return null; } if (autowiredBeanNames != null) { autowiredBeanNames.addAll(matchingBeans.keySet()); } TypeConverter converter = (typeConverter != null ? typeConverter : getTypeConverter()); Object result = converter.convertIfNecessary(matchingBeans.values(), type); if (result instanceof List) { Comparator comparator = adaptDependencyComparator(matchingBeans); if (comparator != null) { ((List) result).sort(comparator); } } return result; }
看上面的注释:// 找到候选者。通过findAutowireCandidates( ... )方法,会返回实现了List 中的范型IOrderAlipayStrategy接口的非抽象类的相关Map。在该方法中会首先调用通过下面代码得到需要被注入的信息,
String[] candidateNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors( this, requiredType, true, descriptor.isEager());

需要简单的看一下该方法的实现,下面源码中的注释处是关键,lbf就是DefaultListableBeanFactory对象,通过它的getBeanNamesForType( ... )方法可以进行类型注入。
public static String[] beanNamesForTypeIncludingAncestors( ListableBeanFactory lbf, Class type, boolean includeNonSingletons, boolean allowEagerInit) {Assert.notNull(lbf, "ListableBeanFactory must not be null"); // 请看这里,关键部分 String[] result = lbf.getBeanNamesForType(type, includeNonSingletons, allowEagerInit); if (lbf instanceof HierarchicalBeanFactory) { HierarchicalBeanFactory hbf = (HierarchicalBeanFactory) lbf; if (hbf.getParentBeanFactory() instanceof ListableBeanFactory) { String[] parentResult = beanNamesForTypeIncludingAncestors( (ListableBeanFactory) hbf.getParentBeanFactory(), type, includeNonSingletons, allowEagerInit); result = mergeNamesWithParent(result, parentResult, hbf); } } return result; }

需要注意的是,这里根据类型注入,并不是自动注入。请看populateBean( ... )方法里的代码片段
if (mbd.getResolvedAutowireMode() == AUTOWIRE_BY_NAME || mbd.getResolvedAutowireMode() == AUTOWIRE_BY_TYPE) { MutablePropertyValues newPvs = new MutablePropertyValues(pvs); // Add property values based on autowire by name if applicable. if (mbd.getResolvedAutowireMode() == AUTOWIRE_BY_NAME) { autowireByName(beanName, mbd, bw, newPvs); } // Add property values based on autowire by type if applicable. if (mbd.getResolvedAutowireMode() == AUTOWIRE_BY_TYPE) { autowireByType(beanName, mbd, bw, newPvs); } pvs = newPvs; }

集合类型的注入虽然用到了getBeanNamesByType,但是在填充属性时,mbd.getResolvedAutowireMode()依然等于0,也就是说这种情况依然属于手动注入。
String[] result = lbf.getBeanNamesForType(type, includeNonSingletons, allowEagerInit); 里面的实现,基本上就是遍历beanDefintionMap,根据类型type去匹配相关的bd,并且返回,此处不在展开讨论。
总结
  1. 集合类型属性的注入可以解决很多业务上的代码问题,比如:某些场景下可以替换switch case,详见:《写出优雅的业务代码(2):优化掉 switch case》
  2. 有个误区需要指出,@Autowired字面意思是自动装配,但是在spring里用@Autowired注解的属性的mbd.getResolvedAutowireMode()值是0。
    源码中的定义如下:
public interface AutowireCapableBeanFactory extends BeanFactory {/** * Constant that indicates no externally defined autowiring. Note that * BeanFactoryAware etc and annotation-driven injection will still be applied. * @see #createBean * @see #autowire * @see #autowireBeanProperties */ int AUTOWIRE_NO = 0;

    推荐阅读