目录
@Autowired注解的使用
@Autowired注解可应用于构造函数、setter方法、具有任意名称和多个参数的方法、字段,或者与构造函数混合使用
@Autowired注解是属于spring的容器配置的一个注解,与它同属容器配置的注解还有:@Required,@Primary, @Qualifier等。因此@Autowired注解是一个用于容器配置的注解。在spring的世界当中,自动装配指的就是使用将Spring容器中的bean自动和我们需要这个bean的类组装在一起。
@Autowired替换autowire属性,可以自动装配(按照类型装配,通过set方法,且方法可以省略)
使用的位置:修饰属性,set方法
使用的语法:@Autowired(required="true")
注意:
1.如果容器中没有一个可以与之匹配且required属性为true则会报异常 :NoSuchBeanDefinitionException
2.如果容器中有多个可以类型可以与之匹配,则自动切换为按照名称装配
3.如果容器中有多个可以类型可以与之匹配,则自动切换为按照名称装配,如果名称也没有匹配,则报异常 :NoUniqueBeanDefinitionException
@Autowired注解是如何实现的
java的注解实现的核心技术是反射,让我们通过一些例子以及自己实现一个注解来理解它工作的原理,例如注解@Override。@Override注解的定义:
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)
public @interface Override {
}
@Override注解使用java官方提供的注解,它的定义里面并没有任何的实现逻辑(所有的注解几乎都是这样的,注解只能是被看作元数据,它不包含任何业务逻辑)。注解更像是一个标签,一个声明,表面被注释的这个地方,将具有某种特定的逻辑。
@Autowired在spring的源代码里的定义:
package org.springframework.beans.factory.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Autowired {
boolean required() default true;
}
在Spring源代码当中,@Autowired注解位于包org.springframework.beans.factory.annotation之中,该包的内容如下:
Spring对@Autowired注解的实现逻辑位于类AutowiredAnnotationBeanPostProcessor之中,其中的核心处理代码如下:
private InjectionMetadata buildAutowiringMetadata(final Class<?> clazz) {
LinkedList<InjectionMetadata.InjectedElement> elements = new LinkedList<>();
Class<?> targetClass = clazz;//需要处理的目标类
do {
final LinkedList<InjectionMetadata.InjectedElement> currElements = new LinkedList<>();
//通过反射获取该类所有的字段,并遍历每一个字段,并通过方法findAutowiredAnnotation遍历每
//一个字段的所用注解,并如果用autowired修饰了,则返回auotowired相关属性
ReflectionUtils.doWithLocalFields(targetClass, field -> {
AnnotationAttributes ann = findAutowiredAnnotation(field);
if (ann != null) {//校验autowired注解是否用在了static方法上
if (Modifier.isStatic(field.getModifiers())) {
if (logger.isWarnEnabled()) {
logger.warn("Autowired annotation is not supported on static fields: " + field);
}
return;
}
boolean required = determineRequiredStatus(ann);
currElements.add(new AutowiredFieldElement(field, required));
}
});
ReflectionUtils.doWithLocalMethods(targetClass, method -> {
Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);
if (!BridgeMethodResolver.isVisibilityBridgeMethodPair(method, bridgedMethod)) {
return;
}
AnnotationAttributes ann = findAutowiredAnnotation(bridgedMethod);
if (ann != null && method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) {
if (Modifier.isStatic(method.getModifiers())) {
if (logger.isWarnEnabled()) {
logger.warn("Autowired annotation is not supported on static methods: " + method);
}
return;
}
if (method.getParameterCount() == 0) {
if (logger.isWarnEnabled()) {
logger.warn("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 new InjectionMetadata(clazz, elements);
}
这个方法返回的是包含所有带有@Autowired注解修饰的一个InjectionMetadata集合。这个类由两部分组成:1.我们处理的目标类,2.如下方法获取到的所有elements集合。
public InjectionMetadata(Class<?> targetClass, Collection<InjectedElement> elements) {
this.targetClass = targetClass;
this.injectedElements = elements;
}
有了目标类,与所有需要注入的元素集合之后,我们就可以实现@Autowired的依赖注入逻辑了,实现的方法如下:
@Override
public PropertyValues postProcessPropertyValues(
PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeanCreationException {
InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);
try {
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;
}
它调用的方法是InjectionMetadata中定义的inject方法,如下
public void inject(Object target, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
Collection<InjectedElement> checkedElements = this.checkedElements;
Collection<InjectedElement> elementsToIterate =
(checkedElements != null ? checkedElements : this.injectedElements);
if (!elementsToIterate.isEmpty()) {
for (InjectedElement element : elementsToIterate) {
if (logger.isTraceEnabled()) {
logger.trace("Processing injected element of bean '" + beanName + "': " + element);
}
element.inject(target, beanName, pvs);
}
}
}
其逻辑就是遍历,然后调用inject方法,inject方法其实现逻辑如下:
/**
* Either this or {@link #getResourceToInject} needs to be overridden.
*/
protected void inject(Object target, @Nullable String requestingBeanName, @Nullable PropertyValues pvs)
throws Throwable {
if (this.isField) {
Field field = (Field) this.member;
ReflectionUtils.makeAccessible(field);
field.set(target, getResourceToInject(target, requestingBeanName));
}
else {
if (checkPropertySkipping(pvs)) {
return;
}
try {
Method method = (Method) this.member;
ReflectionUtils.makeAccessible(method);
method.invoke(target, getResourceToInject(target, requestingBeanName));
}
catch (InvocationTargetException ex) {
throw ex.getTargetException();
}
}
}
使用@Autowired注入的bean对于目标类来说,从代码结构上来讲也就是一个普通的成员变量,@Autowired和spring一起工作,通过反射为这个成员变量赋值,也就是将其赋为期望的类实例。