spring里【集合类型属性】的注入
关键字:
- spring
- 集合类型属性赋值
- List类型属性注入
- spring源码
- getBeanNamesByType
- AUTOWIRE_BY_TYPE
- 定义了一个接口
IOrderAlipayStrategy
public interface IOrderAlipayStrategy {
PayType getPayType();
OrderInfo payThroughAlipay(AlipayConfig alipayConfig,PayType payType, String orderId, String alipayUserId) throws Exception;
}
- 新建一箩筐类,这些类都实现
IOrderAlipayStrategy
接口
@Component
public class ActivityOrderStrategy extends AbstractOrderAlipayStrategy {
/**
省略内部代码
*/
}@Component
public class OrgOrderObjStrategy extends AbstractOrderAlipayStrategy {
/**
省略内部代码
*/
}//
// 省略项目里其它的实现类
//
- 在代码里注入集合属性
@Component
public class OrderStrategyFactory {// 用这个list来装载所有的策略类
@Autowired
private List orderStrategyList;
// 省略其它代码}
【spring里【集合类型属性】的注入】上面的代码里通过@Autowired注解的
orderStrategyList
,将会被实现了范型接口IOrderAlipayStrategy
的非抽象类的实例填充。这样就很容易的为
orderStrategyList
赋值了,他的内容就是系统里实现了IOrderAlipayStrategy
接口的实现类的对象实例。运行截图如下:
文章图片
被注入的集合类型属性
- 恭喜各位,大功告成!不想了解原理的可以撤了 _
- spring环境在初始化的过程中,doCreateBean阶段,会调用
populateBean(beanName, mbd, instanceWrapper);
方法为正在实例化的bean的属性赋值。 - 在
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属性注入相关的逻辑。请看下面断点截图文章图片
@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);
部分,从这里再次劈荆斩棘,最终会来到DefaultListableBeanFactory
的private 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
看上面的注释:// 找到候选者。通过
findAutowireCandidates( ... )
方法,会返回实现了ListString[] 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,并且返回,此处不在展开讨论。总结
- 集合类型属性的注入可以解决很多业务上的代码问题,比如:某些场景下可以替换switch case,详见:《写出优雅的业务代码(2):优化掉 switch case》
- 有个误区需要指出,@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;