场景
我在研究为什么SpringBoot框架不推荐使用@Autowired注解的时候,突然想到一个问题,@Autowired
注解是否是通过setter方法注入的?
@Autowired
基本用法
首先,@Autowired基本用法如下:
- 注解在类成员属性上
- 注解在setter方法上
- 注解在类构造器上
我这里为了验证问题,仅使用字段的方式看看
基于字段的方式
请看下面的例子:
@RestController
@Api(tags = "用户前端控制器")
public class UserController {
@Autowired
private UserService userService;
@PostMapping(value="/testUserService")
@ApiOperation(value="测试userService的注入")
public String testUserService(){
return String.valueOf(userService==null);
}
}
上面的例子执行后:
这里可以看到,userService即使没有setter方法,还是能够注入成功的,说明了@Autowired的注入并不是依靠setter方法注入的。
究竟@Autowired是怎么样注入的?
第一点,首先我想看看是不是有UserController自动产生了setter方法。
通过jclasslib分析字节码,结果如下图,只看到两个方法,所以@Autowired没有自动产生setter方法。
那么,既然不是通过setter方法,也不是通过构造器注入的话,在我印象中还可以通过反射手段进行赋值。
AutowiredAnnotationBeanPostProcessor
类
该类是@Autowired的具体实现类,先预览一下类方法,IDEA快捷键Ctrl+F12
有机会介入到Bean的创建过程,只有后置处理的那几个方法,postProcessXXX,而且有一个方法是已过时的。现在看看它们做了什么。
postProcessMergedBeanDefinition
这个方法是实现MergedBeanDefinitionPostProcessor
接口的方法,看起来像是收集元信息然后封装为InjectionMetadata
@Override
public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
// 1. 寻找bean中所有被@Autowired注释的属性,并将属性封装成InjectedElement类型
InjectionMetadata metadata = findAutowiringMetadata(beanName, beanType, null);
metadata.checkConfigMembers(beanDefinition);
}
postProcessProperties
:注入过程
这个方法是实现InstantiationAwareBeanPostProcessor
接口的方法
@Override
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
// 1. 寻找通过@Autowired注解的属性或者方法
InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);
try {
// 2. 注入
metadata.inject(bean, beanName, pvs);
}
catch (BeanCreationException ex) {
throw ex;
}
catch (Throwable ex) {
throw new BeanCreationException(beanName, "Injection of autowired dependencies failed", ex);
}
return pvs;
}
回顾一下Bean实例创建的流程,路径是AbstractApplicationContext.refresh()->finishBeanFactoryInitialization()->getBean()
方法。
getBean方法的流程大致可以分为创建实例,填充实例,初始化实例三步。
我经过debug验证的结论:
在实例化阶段,会调用MergedBeanDefinitionPostProcessor
的postProcessMergedBeanDefinition
的方法,AutowiredAnnotationBeanPostProcessor
的postProcessMergedBeanDefinition
方法,作用是将有@Autowired
注解的成员扫描出来,封装为InjectionMetadata
,在实例化上面的UserController的时候,刚好就是size = 1;
调用上面说到的postProcessMergedBeanDefinition
方法
检测出@Autowried
注解的成员
在填充阶段,AutowiredAnnotationBeanPostProcessor
的postProcessorProperties
方法会被调用,作用是解析InjectionMetadata
,并使用反射,从容器中获取实例设置到成员变量中。
/**
* 这个方法是在AutowiredAnnotationBeanPostProcessor 中
*/
@Override
protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
//获取Field对象
Field field = (Field) this.member;
//value赋值
Object value;
if (this.cached) {
value = resolvedCachedArgument(beanName, this.cachedFieldValue);
}
//...
value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);
//...
//调用Field.set方法设置赋值
if (value != null) {
ReflectionUtils.makeAccessible(field);
field.set(bean, value);
}
}
}
结论
@Autowired
可以不需要setter方法,因为在AutowiredAnnotationBeanPostProcessor
中的inject
方法显示,是通过反射手段填充的。
参考
【https://blog.csdn.net/qq_19782019/article/details/85038081】
【https://mp.weixin.qq.com/s/_OL0jR1eJoD9oM4Og9ZzjA】