Spring5.2.x-03-自动注入模型
知识点笔记
- spring是对构造方法做推断来实例化bean
- Spring有自己的推断模型, 改变推断模型会改变Spring对构造方法的选择
AbstractAutowireCapableBeanFactory抽象类中的createBeanInstance方法里的一行代码
// 推测需要的构造方法
Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
无参构造方法为 null, 会通过clazz.getDeclaredConstructor();最后走反射ctor.newInstance(argsWithDefaultValues);获取
但内部类不会, Spring会默认编入一个传入父类作为参数的构造方法
手动注入
通过xml明确指定如何注入 NO = 0
自动注入
AbstractBeanDefinition.AUTOWIRE_BY_NAME = 1
AbstractBeanDefinition.AUTOWIRE_BY_TYPE = 2
AutowireCapableBeanFactory.AUTOWIRE_CONSTRUCTOR = 3
@Autowired是自动注入还是手动注入?
依赖注入是一种过程, 文档上说是基于构造方法的注入和基于Setter方法的注入
根据类型和根据名字的区别
ByType和ByName的区别
比如有一个方法
public void setByType(N n) {
log.debug("setter N:{}",n);
}
byNmae, 用的是beanName, 理论上就是n
byType, 用的是set后面的名字, byType
@AutoWired和@Resource的主要区别
@AutoWired
先根据类型, 再根据名字
不仅仅是先根据类型找, 先找到a和b, 再根据名字去筛选, 找到一个
@Resource
先根据名字, 再根据类型
@AutoWired的工作原理
AutowiredAnnotationBeanPostProcessor, 可以加到属性上, 可以加到方法上, 用两个内部类
629行左右的inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs)方法解析
解析
value = resolveFieldValue(field, bean, beanName);
->DefaultListableBeanFactory#resolveMultipleBeans
resolveMultipleBeans(): 如果是array/list/map等, 走这里来解析完成查找, 把所有的bean直接注入进来
获取类型(拿到class): Class<?> type = descriptor.getDependencyType();
findAutowireCandidates(): 先根据类型找到该类型所有类的bean名字String[] candidateNames, 如果找到多个就放到map里, 再根据名字(实例名字)来找, 找到一个就返回
@Resource的工作原理
CommonAnnotationBeanPostProcessor和AutowiredAnnotationBeanPostProcessor, 两者都有的方法postProcessProperties()方法, 一个找标记@Autowired的一个找@Resource的
AutowiredAnnotationBeanPostProcessor#postProcessProperties => 会扫描出有@Autowired的玩意(field或method), 放到InjectionMetadata的属性injectedElements集合里
遍历injectedElements集合, 调用每个对象(InjectedElement)的inject方法, @Autowired的InjectedElement重写了Field和Method方法(先类型再名字), @Resource的InjectedElement用的是父类的,
@Resource查找bean
autowireResource()方法来查找
根据名字判断容器当中是否有一个名字为属性名字的bean(单例池或者是与之对应的BeanDefinition)如果找到了, 就返回了, 如果找不到, 再根据类型去找
如果@Resource(name="aaa")注解给了值, 说明是一定要注入name为aaa的bean, 所以需要找到这个bean, 找不到对应的就报错
如果只是field的名字不一样, 比如 A aaa, 那么就是说, 需要一个name为aaa的bean, 如果没有, 就去找一个类型为A的bean(这里的流程和@Autowired一样), 不是强制要name为aaa的bean