Spring5.2.x-03-自动注入模型

知识点笔记

  1. spring是对构造方法做推断来实例化bean
  2. 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

posted @ 2022-08-04 09:31  RichardHaha  阅读(28)  评论(0编辑  收藏  举报