@Autowired的几种用法
- 作用在属性上
- 作用在方法上
- 作用在构造器上
demo演示
创建三个普通bean
@Component
public class ComponentA {
}
@Component
public class ComponentB {
}
@Component
public class ComponentC {
}
依赖注入
package com.test.model.component;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class MixComponent {
@Autowired
private ComponentA componentA;
private ComponentB componentB;
private ComponentC componentC;
@Autowired
public void setComponentB(ComponentB componentB) {
this.componentB = componentB;
}
public MixComponent() {
}
@Autowired
public MixComponent(ComponentC componentC) {
this.componentC = componentC;
}
}
主要流程
对@Autowired注解生效的相关BeanPostProcessor是AutowiredAnnotationBeanPostProcessor,它会在bean实例化的多个阶段,对bean进行处理
具体方法
- determineCandidateConstructors : 推断构造方法
- postProcessMergedBeanDefinition : 发现注入点
- postProcessProperties : 属性注入
推断构造方法相关博文 : Spring之推断构造方法
发现注入点
AutowiredAnnotationBeanPostProcessor#postProcessMergedBeanDefinition
AutowiredAnnotationBeanPostProcessor#findAutowiringMetadata
AutowiredAnnotationBeanPostProcessor#buildAutowiringMetadata
private InjectionMetadata buildAutowiringMetadata(Class<?> clazz) {
// 判断class是否存在@Autowired、@Value注解,如果不存在,直接就不处理
if (!AnnotationUtils.isCandidateClass(clazz, this.autowiredAnnotationTypes)) {
return InjectionMetadata.EMPTY;
}
List<InjectionMetadata.InjectedElement> elements = new ArrayList<>();
Class<?> targetClass = clazz;
do {
final List<InjectionMetadata.InjectedElement> currElements = new ArrayList<>();
ReflectionUtils.doWithLocalFields(targetClass, field -> {
// 获取field上@Autowired、@Value注解信息
MergedAnnotation<?> ann = findAutowiredAnnotation(field);
if (ann != null) {
// 如果field是static则不处理
if (Modifier.isStatic(field.getModifiers())) {
if (logger.isInfoEnabled()) {
logger.info("Autowired annotation is not supported on static fields: " + field);
}
return;
}
// 判断是否必须
// @Autowired注解:属性required == true表示必须
// @Value注解:必须
boolean required = determineRequiredStatus(ann);
currElements.add(new AutowiredAnnotationBeanPostProcessor.AutowiredFieldElement(field, required));
}
});
ReflectionUtils.doWithLocalMethods(targetClass, method -> {
Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);
if (!BridgeMethodResolver.isVisibilityBridgeMethodPair(method, bridgedMethod)) {
return;
}
// 获取method上@Autowired、@Value注解信息
MergedAnnotation<?> ann = findAutowiredAnnotation(bridgedMethod);
if (ann != null && method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) {
// 如果method是static则不处理
if (Modifier.isStatic(method.getModifiers())) {
if (logger.isInfoEnabled()) {
logger.info("Autowired annotation is not supported on static methods: " + method);
}
return;
}
// 如果method参数个数是0则不处理
if (method.getParameterCount() == 0) {
if (logger.isInfoEnabled()) {
logger.info("Autowired annotation should only be used on methods with parameters: " +
method);
}
}
// 判断是否必须
// @Autowired注解:属性required == true表示必须
// @Value注解:必须
boolean required = determineRequiredStatus(ann);
// 如果方法是setXxx或者getXxx,则利用Spring自省机制获取PropertyDescriptor对象
PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);
currElements.add(new AutowiredAnnotationBeanPostProcessor.AutowiredMethodElement(method, required, pd));
}
});
elements.addAll(0, currElements);
targetClass = targetClass.getSuperclass();
}
while (targetClass != null && targetClass != Object.class);
return InjectionMetadata.forElements(elements, clazz);
}
小结
如果field或者method上存在@Autowired或者@Value注解,则Spring会将其解析成一个注入点。field会被解析成AutowiredFieldElement,method会被解析成AutowiredMethodElement
注意点
- field或者method不能是static,否则不处理
- method的参数个数必须大于0
属性注入
AutowiredAnnotationBeanPostProcessor#postProcessProperties
注意这里的metadata不是我们方法点进去的InjectionMetadata,而是AutowiredAnnotationBeanPostProcessor的内部类
- AutowiredFieldElement
- AutowiredMethodElement
AutowiredFieldElement#inject
AutowiredMethodElement#inject
注入Field
AutowiredAnnotationBeanPostProcessor#resolveFieldValue
DefaultListableBeanFactory#resolveDependency
DefaultListableBeanFactory#doResolveDependency
Spring中细节一般都是在doXxx这样的方法中,所以我们要重点关注
1.处理@Value注解
大概有下列几种用法
- @Value("${xxx}") : 获取当前环境中名称为xxx的属性值
- @Value("${xxx:8080}") : 获取当前环境中名称为xxx的属性值,如果不存在,使用默认值8080
- @Value("${${xxx}}") :假设当前环境中属性xxx的值为yyy,则表达式获取的为环境中名称为yyy的属性值
- @Value("#{xxx}") : 获取当前容器中名称为xxx的bean
@Value相关博文 : Spring之@Value注解
2.处理集合类依赖
集合类依赖的处理过程我们不重点说明,因为其底层也是调用单体依赖的逻辑,主要演示其用法
创建一个接口和实现其接口的两个bean
public interface Animal {
}
@Component
public class Cat implements Animal {
}
@Component
public class Fish implements Animal {
}
创建类型为House的bean
@Component
public class House {
@Autowired
private List<Animal> list;
@Autowired
private Map<String, Animal> map;
@Autowired
private Animal[] array;
}
查看运行结果
3.处理单体依赖
DefaultListableBeanFactory#findAutowireCandidates
注入特定类型的bean
Spring期望你在注入某些特定类型的bean时候,使用的是它预先设置的bean,而不是用户自定义的bean
相关源码AbstractApplicationContext#prepareBeanFactory
demo演示
@Component
public class Person {
// 这种情况下会注入Spring容器中的beanFactory
@Autowired
private BeanFactory beanFactory;
}
添加候选者
什么是SelfReference
@Configuration
public class SelfReference {
// 第一种情况下的selfReference
@Autowired
private SelfReference selfReference;
// 第二种情况下的selfReference
@Autowired
private InnerReference innerReference;
@Bean
public InnerReference innerReference() {
return new InnerReference();
}
static class InnerReference {
}
}
isAutowireCandidate
isAutowireCandidate的方法调用栈有很多同名方法,我们分析最核心的一个
DefaultListableBeanFactory#isAutowireCandidate
这里的resolver是的类型是QualifierAnnotationAutowireCandidateResolver
查看类结构
- SimpleAutowireCandidateResolver : 判断bd是否是isAutowireCandidate
- GenericTypeAwareAutowireCandidateResolver : 处理泛型
- QualifierAnnotationAutowireCandidateResolver : 处理@Qualifier注解
BeanDefinitionHolder对象必须满足上述三个类的isAutowireCandidate方法都返回true,才表示此BeanDefinitionHolder对象是一个候选bd
演示SimpleAutowireCandidateResolver#isAutowireCandidate返回false的情况
创建一个类型为Foo的bean,并复用上文代码
@Component
public class Foo {
}
@Component
public class Person {
// 这种情况下会注入Spring容器中的beanFactory
@Autowired
private BeanFactory beanFactory;
@Autowired(required = false)
private Foo foo;
}
创建一个bfpp,将foo的AutowireCandidate的值设为false
@Component
public class FirstBeanFactoryPostProcessor implements BeanDefinitionRegistryPostProcessor {
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
BeanDefinition beanDefinition = registry.getBeanDefinition("foo");
// 设置其不是候选者
beanDefinition.setAutowireCandidate(false);
}
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
}
}
属性foo注入失败
演示会校验泛型的情况
创建Book类,以及实现该类的两个bean
public class Book {
}
@Component
public class EnglishBook extends Book{
}
@Component
public class MathBook extends Book{
}
改造Person代码
@Component
public class Person {
@Autowired
private List<? extends Book> books;
}
@Qualifier相关博文 : Spring之@Qualifier注解
推断最适合的bean
DefaultListableBeanFactory#determineAutowireCandidate
protected String determineAutowireCandidate(Map<String, Object> candidates, DependencyDescriptor descriptor) {
Class<?> requiredType = descriptor.getDependencyType();
// 如果仅有一个候选者所属class上存在@Primary注解,则返回该候选者
// 如果存在多个候选者所属class上存在@Primary注解,则抛出异常
String primaryCandidate = determinePrimaryCandidate(candidates, requiredType);
if (primaryCandidate != null) {
return primaryCandidate;
}
// 判断候选者所属class上是否存在注解@Priority注解
// 如果存在,返回优先级最高的候选者
String priorityCandidate = determineHighestPriorityCandidate(candidates, requiredType);
if (priorityCandidate != null) {
return priorityCandidate;
}
// 判断候选者的candidateName和属性名称是否一致,如果一致返回该候选者
for (Map.Entry<String, Object> entry : candidates.entrySet()) {
String candidateName = entry.getKey();
Object beanInstance = entry.getValue();
if ((beanInstance != null && this.resolvableDependencies.containsValue(beanInstance)) ||
matchesBeanName(candidateName, descriptor.getDependencyName())) {
return candidateName;
}
}
return null;
}
测试代码
@Component
public class TestBean {
@Autowired
private PrimaryTest primaryTest;
@Autowired
private PriorityTest priorityTest;
@Autowired
private BeanNameTest secondBeanName;
}
public interface PrimaryTest {
}
@Component
@Primary
public class FirstPrimaryBean implements PrimaryTest {
}
@Component
public class SecondPrimaryBean implements PrimaryTest {
}
public interface PriorityTest {
}
@Component
@Priority(1)
public class FirstPriorityBean implements PriorityTest {
}
@Component
@Priority(2)
public class SecondPriorityBean implements PriorityTest {
}
public interface BeanNameTest {
}
@Component
public class FirstBeanName implements BeanNameTest {
}
@Component
public class SecondBeanName implements BeanNameTest {
}
查看运行结果
方法的注入和属性的注入类似,主要还是doResolveDependency方法,这里就不再赘述