目录
讲解之前我们先来看下视频!!!
趣味Spring-2分钟动画讲解@Autowired是如何工作的
在Spring框架中 @Autowired是一种注解,可以对成员变量、方法和构造函数进行标注,来完成自动装配的工作,@Autowired标注可以放在成员变量上,也可以放在成员变量的set方法上,也可以放在任意方法上表示,自动执行当前方法,如果方法有参数,会在IOC容器中自动寻找同类型参数为其传值。
Spring 2.5 引入了 @Autowired 注释,它可以对类成员变量、方法及构造函数进行标注,完成自动装配的工作。 通过 @Autowired的使用来消除 set ,get方法。
@Autowired注解用法
将@Autowired注释应用于方法
将@Autowired注释应用于属性上
@Autowired注解是干什么用的
@Autowired从所属范围来看,事实上属于spring的容器配置的一个注解,与它同属容器配置的注解还有:
@Primary
含义:在类型冲突情况下此注解修饰的类作为首选项,
位置:修饰类
注意:不能单独使用
@Qualifier(value="名称")
含义:按照名称装配
位置:修饰成员变量
注意:不能单独使用,必须与@Autowire联合使用
@Resource(name="名称")
含义:按照名称装配,指定一个ID名称固定使用
位置:修饰成员变量
注意:单独使用
@Scope
含义:作用域
位置:修饰类
语法:@Scope("singleton")
@Scope("prototype")
@Scope(ConfigurableBeanFactory.SCOPE_SINGLETON)
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
自动装配
然而从字面上来看@autowired注解来源于英文单词autowire,这个单词的意思是自动装配的意思。自动装配又是什么意思?这个词语本来的意思是指的一些工业上的用机器代替人口,自动将一些需要完成的组装任务,或者别的一些任务完成。而在spring的世界当中,自动装配指的就是使用将Spring容器中的bean自动的和我们需要这个bean的类组装在一起,并且Spring利用依赖注入(DI)完成对IOC容器中各个组件的依赖关系赋值
@Autowired自动注入:
(1)默认优先按照类型去容器中找对应的组件:applicationContext.getBean()
(2)如果找到多个相同类型的组件,再将属性的名称作为组件的ID去容器中查找
源码分析
@Autowired 注解是由 AutowiredAnnocationBeanPostProcessor 来处理的。Spring会在实例化Bean时有两个触发点:
在方法 postProcessMergedBeanDefinition 中,查找该Bean是否有 @Autowired
注解
在方法 populateBean 进行属性注入时,也会查找该Bean是否有 @Autowired 注解。
public class AutowiredAnnotationBeanPostProcessor implements SmartInstantiationAwareBeanPostProcessor,
MergedBeanDefinitionPostProcessor, PriorityOrdered, BeanFactoryAware {
// 省略其他属性和方法
// postProcessMergedBeanDefinition方法会调用这个入口点
@Override
public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
InjectionMetadata metadata = findAutowiringMetadata(beanName, beanType, null);
metadata.checkConfigMembers(beanDefinition);
}
// populateBean方法会调用这个入口点
@Override
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
// ....
InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);
// 对bean对象进行属性注入
metadata.inject(bean, beanName, pvs);
}
}
findAutowiringMetadata()
findAutowiringMetadata()方法是用来查找类的字段、构造函数、方法是否被 @Autowired 标记;如果有,就把字段、构造函数、方法封装成一个注入点 InjectionElement。
findAutowiringMetadata()方法先从注入点缓存中查找,是否有被缓存过的,有就直接返回;没有就调用 buildAutowiringMetadata 方法对类的字段、方法、构造函数进行解析、查找 @Autowired,并向父类上继续查找。这里直接来看 buildAutowiringMetadata 方法。
private InjectionMetadata buildAutowiringMetadata(final Class<?> clazz) {
// 判断指定类是否是 @Autowire @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<>();
// 在类的字段上找@Autowired注解
ReflectionUtils.doWithLocalFields(targetClass, field -> {
MergedAnnotation<?> ann = findAutowiredAnnotation(field);
if (ann != null) {
if (Modifier.isStatic(field.getModifiers())) {
if (logger.isInfoEnabled()) {
logger.info("Autowired annotation is not supported on static fields: " + field);
}
return;
}
boolean required = determineRequiredStatus(ann);
currElements.add(new AutowiredFieldElement(field, required));
}
});
// 在类的构造函数和方法上找@Autowired注解
// 主要:方法不能是静态方法
ReflectionUtils.doWithLocalMethods(targetClass, method -> {
Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);
if (!BridgeMethodResolver.isVisibilityBridgeMethodPair(method, bridgedMethod)) {
return;
}
MergedAnnotation<?> ann = findAutowiredAnnotation(bridgedMethod);
if (ann != null && method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) {
if (Modifier.isStatic(method.getModifiers())) {
if (logger.isInfoEnabled()) {
logger.info("Autowired annotation is not supported on static methods: " + method);
}
return;
}
if (method.getParameterCount() == 0) {
if (logger.isInfoEnabled()) {
logger.info("Autowired annotation should only be used on methods with parameters: " +
method);
}
}
boolean required = determineRequiredStatus(ann);
PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);
currElements.add(new AutowiredMethodElement(method, required, pd));
}
});
elements.addAll(0, currElements);
targetClass = targetClass.getSuperclass();
}
while (targetClass != null && targetClass != Object.class);
return InjectionMetadata.forElements(elements, clazz);
}
inject()
inject 方法就是属性的入口。AutowiredMethodElement 和 AutowiredFieldElement 分别代表字段注入、方法注入点。接下来看一下 AutowiredFieldElement 的 inject 方法。
这个方法大概逻辑:如果该注入点已经被注入过(this.cached=true),就直接从缓存中获取;否则就有解析这个字段,从BeanFactory容器中找到合适的候选Bean,最后通过 field.set(bean, value) 注入。
protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
Field field = (Field) this.member;
Object value;
if (this.cached) {
try {
value = resolvedCachedArgument(beanName, this.cachedFieldValue);
}
catch (NoSuchBeanDefinitionException ex) {
// Unexpected removal of target bean for cached argument -> re-resolve
value = resolveFieldValue(field, bean, beanName);
}
}
else {
value = resolveFieldValue(field, bean, beanName);
}
if (value != null) {
ReflectionUtils.makeAccessible(field);
field.set(bean, value);
}
}
从源码中我们看到,核心逻辑就是通过beanFactory.resolveDependency()方法从bean工厂中获取依赖的对象。跟踪一下resolveDependency()方法可以发现,底层会调用到org.springframework.beans.factory.config.DependencyDescriptor#resolveCandidate()方法,而resolveCandidate()方法内部其实是通过beanFactory.getBean("类对象")从bean容器中获取到这个bean对象。
注意:
1.@Autowire默认按照类型装配
2.如果spring容器中没有可以与之匹配的类,则会报异常
NoSuchBeanDefinitionException
3.如果spring容器中有多个类型可以与之匹配,@Autowire注解会自动切换为按照名称装配,如果还没有则会报错
NoUniqueBeanDefinitionException
总结
- 根据Class目标类类型,通过反射获取其所有的Field和Method信息,然后判断字段或者方法上面是否添加了@Autowired和@Value注解,以此来判断是否需要自动装配;
- 如果标注有@Autowired和@Value注解,表示需要自动装配,则会将需要自动装配的元素,封装成AutowiredFieldElement(针对字段)或AutowiredMethodElement(针对方法)对象;
- 调用AutowiredFieldElement或AutowiredMethodElement的inject方法,通过反射,调用容器的getBean()方法找到需要注入的Bean对象,然后注入到目标Bean中;