目录
前言
在分析这个注解实现原理之前,我们先回顾下@Autowired注解的用法。
一、@Autowired注解的用法
1.@Autowired注解应用于构造方法,示例如下:
@Autowired
public OrderService(UserService userService){
this.userService = userService;
}
@Autowired加在构造方法上时,Spring会在推断构造方法阶段,选择该构造方法来进行实例化,在反射调用构造方法之前,会先根据构造方法参数类型、参数名从Spring容器中找到Bean对象,当做构造方法入参。
2.@Autowired注解应用于属性上,示例如下:
@Autowired
private IUserService Service;
@Autowired加在某个属性上,Spring在进行Bean的生命周期过程中,在属性填充这一步,会基于实例化出来的对象,对该对象中加了@Autowired的属性自动给属性赋值。Spring会先根据属性的类型去Spring容器中找出该类型所有的Bean对象,如果找出来多个,则再根据属性的名字从多个中再确定一个,如果required属性为true,并且根据属性信息找不到对象,则直接抛异常。
3.@Autowired注解应用于方法上,示例如下:
@Autowired
public void setUserService(UserService userService){
this.userService = userService;
}
@Autowired注解写在某个方法上时,Spring在Bean生命周期的属性填充阶段,会根据方法的参数类型、参数名字从Spring容器找到对象当做方法入参,自动反射调用该方法。
二、@Autowired注解自动装配的过程
@Autowired通过Bean的后置处理器进行解析的
1.在创建一个Spring上下文的时候在构造函数中进行注册AutowiredAnnotationBeanPostProcessor
2.在Bean的创建过程中进行解析:
2.1预解析(解析@Autowired标注的属性、方法, 比如:把属性的类型、名称、属性所在的类...元数据缓存起来;
2.2在属性注入真正的解析(拿到上一步缓存的元数据去IOC容器进行查找,并且返回注入);
a.首先根据预解析的元数据拿到类型去容器中进行查找:
· 如果查询结果没有可以与之匹配的类,则会报异常NoSuchBeanDefinitionException
· 如果查询结果刚好为一个,就将该bean装配给@Autowired指定的数据;
· 如果查询结果不止一个,那么@Autowired会根据名称来查找,如果还没有则会报错NoUniqueBeanDefinitionException
三、@Autowired注解的源码分析
在Spring源代码当中,Autowired注解位于包org.springframework.beans.factory.annotation之中,该包的内容如下:
经过分析,不难发现Spring对autowired注解的实现逻辑位于 类AutowiredAnnotationBeanPostProcessor之中,已在上图标红。其中的核心处理代码如下:
public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
InjectionMetadata metadata = this.findAutowiringMetadata(beanName, beanType, (PropertyValues)null);
metadata.checkConfigMembers(beanDefinition);
}
postProcessMergedBeanDefinition()方法的作用是找到需要自动装配的元素,构建元数据信息,然后封装到AutowiredFieledElement或AutowiredMethodElement中,然后在调用其中的inject方法,通过反射,调用容器的getBean()方法找到需要注入的Bean对象,然后注入到Bean中。
protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
if (!this.checkPropertySkipping(pvs)) {
Method method = (Method)this.member;
Object[] arguments;
if (this.cached) {
try {
arguments = this.resolveCachedArguments(beanName);
} catch (NoSuchBeanDefinitionException var8) {
arguments = this.resolveMethodArguments(method, bean, beanName);
}
} else {
arguments = this.resolveMethodArguments(method, bean, beanName);
}
if (arguments != null) {
try {
ReflectionUtils.makeAccessible(method);
method.invoke(bean, arguments);
} catch (InvocationTargetException var7) {
throw var7.getTargetException();
}
}
}
}