@Autowired 的作用是什么?
1、@Autowired 是一个注释,它可以对类成员变量、方法及构造函数进行标注,让 spring 完成 bean 自动装配的工作。
@Autowired 默认是按照类去匹配,配合 @Qualifier 指定按照名称去装配 bean。
可以这样理解为何需要@Autowired注入,以及@Autowired注释的作用spring可以自动帮你把Bean里面引用的对象的setter/getter方法省略,它会自动帮你set/get(其实是通过反射技术实现的)。
@Autowired注释进行自动注入时,spring容器中匹配的候选Bean数目必须有且仅有一个。
当找不到一个匹配的Bean时,spring容器将抛出BeanCreationException异常,并指出必须至少拥有一个匹配的Bean。
如果spring容器中拥有多个候选Bean,spring容器在启动时也会抛出BeanCreationException
这个时候就可以借助@Qualifier注释指定注入Bean的名称,这样@Autowired遇到多个候选Bean的问题也就解决了。
注意:(1.Autowired自动注入如果匹配到多个类型会注入属性名和beanID一致的bean,如果匹配到多个bean且所有bean的id和属性名都不一致,才需要Qualifier注解指定bean的id 2.Autowired不是自动帮我们get/set,他是通过反射直接赋值给属性的)(@Autowired类型相同指的是bean中的class)(在下面的情况中class相同时,需要借助于注解@Qualifier的帮助,通过它提供的name确认需要的注入的哪一个bean)
<bean name="comment1" class="com.sss.exchanger.Comment">
<property name="content" value="Content of the 1st comment" />
</bean>
<bean name="comment2" class="com.sss.exchanger.Comment">
<property name="content" value="Content of the 2nd comment" />
</bean>
注解解析器:AutowiredAnnotationBeanPostProcessor
- Spring容器启动时,AutowiredAnnotationBeanPostProcessor被注册到容器;
- 扫描代码,如果带有@Autowired注解,则将依赖注入信息封装到InjectionMetadata中(见扫描过程);
- 创建bean时(实例化对象和初始化),会调用各种BeanPostProcessor对bean初始化,AutowiredAnnotationBeanPostProcessor负责将相关的依赖注入进来;
@Autowired扫描过程
- 扫描当前类中标注@Autowired的属性和方法;
- 再查找父类中注@Autowired的属性和方法,依次遍历;
1 @Autowired 干嘛的?
用来执行依赖注入.每当一个Spring管理的bean发现有该注解时,会直接注入相应的另一个Spring管理的bean.
1.1 不同地放置有不同作用
- 属性
Spring将通过扫描自定义的package或通过在配置文件中直接查找bean - 方法
使用@Autowired注解的每个方法都要用到依赖注入
但要注意的是,签名中呈现的所有对象都必须是Spring所管理的bean
如果你有一个方法,比如setTest(Article article, NoSpringArticle noSpringArt),其中只有一个参数 (Article article)是由Spring管理的,那么就将抛出一个org.springframework.beans.factory.BeanCreationException异常
这是由于Spring容器里并没有指定的一个或多个参数所指向的bean,所以也就无法解析它们
1.2 bean的注入方式
- 名称
bean解析是通过bean名称 - 类型
解析基于bean的类型
1.3 @Qualifier 协作
如下相同类型的bean
<bean name="article1" class="com.sss.Article"><property name="text" value="Content of the 1st Article" />
</bean><bean name="article2" class="com.sss.Article"><property name="text" value="Content of the 2nd Article" />
</bean>
假如只是一个简单的@Autowired,Spring根本不知道你要注入哪个bean。这就需要@Qualifier(value =“beanName”)协作.
譬如,要从 com.javaedge.Article类型的bean中区分article1,article2:
@Qualifier(value="article1")
@Autowired
private Article firstArticle;@Qualifier(value="article2")
@Autowired
private Article secondArticle;
2 优雅地使用@Autowired
启动自动注入
<context:annotation-config />
放在应用程序上下文配置。可以使在遇到@Autowired注解时启用依赖注入
- bean
// beans first
public class Comment {private String content;public void setContent(String content) {this.content = content;}public String getContent() {return this.content;}}// sample controller
@Controller
public class TestController {@Qualifier(value="comment1")@Autowiredprivate Comment firstComment;@Qualifier(value="comment2")@Autowiredprivate Comment secondComment;@RequestMapping(value = "/test", method = RequestMethod.GET)public String test() {System.out.println("1st comment text: "+firstComment.getText());System.out.println("2nd comment text: "+secondComment.getText());return "test";}}// no-Spring managed class
public class TestNoSpring {@Autowiredprivate Comment comment;public void testComment(String content) {if (comment == null) {System.out.println("Comment's instance wasn't autowired because this class is not Spring-managed bean");} else {comment.setContent(content);System.out.println("Comment's content: "+comment.getContent());}}}
- 配置
<bean name="comment1" class="com.sss.exchanger.Comment"><property name="content" value="Content of the 1st comment" />
</bean><bean name="comment2" class="com.sss.exchanger.Comment"><property name="content" value="Content of the 2nd comment" />
</bean>
打开http://localhost:8080/test来运行TestController
TestController的注解字段正确地自动注入,而TestNoSpring的注解字段并没有注入进去
1st comment text: Content of the 1st comment
2nd comment text: Content of the 2nd comment
Comment's instance wasn't autowired because this class is not Spring-managed bean
哪里不对 ?TestNoSpring类不由Spring所管理
这就是为什么Spring不能注入Comment实例的依赖
3 隐藏在@Autowired注解背后的秘密
Spring管理可用于整个应用程序的Java对象bean,我们不需要处理他们的生命周期(初始化,销毁)。该任务由此容器来完成。
该上下文具有入口点,在Web应用程序中,是dispatcherservlet。
容器(也就是该上下文)会在它那里被启动并且所有的bean都会被注入
看<context:annotation-config />的定义
<xsd:element name="annotation-config"><xsd:annotation><xsd:documentation><![CDATA[Activates various annotations to be detected in bean classes: Spring's @Required and@Autowired, as well as JSR 250's @PostConstruct, @PreDestroy and @Resource (if available),JAX-WS's @WebServiceRef (if available), EJB 3's @EJB (if available), and JPA's@PersistenceContext and @PersistenceUnit (if available). Alternatively, you maychoose to activate the individual BeanPostProcessors for those annotations.Note: This tag does not activate processing of Spring's @Transactional or EJB 3's@TransactionAttribute annotation. Consider the use of the <tx:annotation-driven>tag for that purpose.See javadoc for org.springframework.context.annotation.AnnotationConfigApplicationContextfor information on code-based alternatives to bootstrapping annotation-driven support.]]></xsd:documentation></xsd:annotation></xsd:element>
类内部的注解,如@Autowired、@Value、@Required、@Resource以及Web Serivce相关的注解,是容器对Bean对象实例化和依赖注入时,通过容器中注册的Bean后置处理器处理这些注解的
所以配置了上面这个配置(<context:component-scan>假如有配置这个,那么就可以省略<context:annotation-config />)后,将隐式地向Spring容器注册AutowiredAnnotationBeanPostProcessor、CommonAnnotationBeanPostProcessor、RequiredAnnotationBeanPostProcessor、PersistenceAnnotationBeanPostProcessor以及这4个专门用于处理注解的Bean后置处理器。
当 Spring 容器启动时,AutowiredAnnotationBeanPostProcessor 将扫描 Spring 容器中所有 Bean
当发现 Bean 中拥有@Autowired 注解时就找到和其匹配(默认按类型匹配)的 Bean
并注入到对应的地方中去。
4 源码分析
通过org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor可以实现依赖自动注入
通过这个类来处理@Autowired @Value Spring
它也可以管理JSR-303的@Inject
- 在
AutowiredAnnotationBeanPostProcessor构造函数中定义要处理的注解

之后,有几种方法对@Autowired处理
第一个,private InjectionMetadata buildAutowiringMetadata(final Class<?> clazz)解析等待自动注入类的所有属性。它通过分析所有字段和方法并初始化org.springframework.beans.factory.annotation.InjectionMetadata类的实例来实现。
private InjectionMetadata buildAutowiringMetadata(final Class<?> clazz) {LinkedList<InjectionMetadata.InjectedElement> elements = new LinkedList<>();Class<?> targetClass = clazz;do {final LinkedList<InjectionMetadata.InjectedElement> currElements = new LinkedList<>();//分析所有字段ReflectionUtils.doWithLocalFields(targetClass, field -> {//findAutowiredAnnotation(field)此方法后面会解释AnnotationAttributes ann = findAutowiredAnnotation(field);if (ann != null) {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);//返回一个InjectionMetadata初始化的对象实例return new InjectionMetadata(clazz, elements);}
.../*** 'Native' processing method for direct calls with an arbitrary target instance,* resolving all of its fields and methods which are annotated with {@code @Autowired}.* @param bean the target instance to process* @throws BeanCreationException if autowiring failed*/public void processInjection(Object bean) throws BeanCreationException {Class<?> clazz = bean.getClass();InjectionMetadata metadata = findAutowiringMetadata(clazz.getName(), clazz, null);try {metadata.inject(bean, null, null);}catch (BeanCreationException ex) {throw ex;}catch (Throwable ex) {throw new BeanCreationException("Injection of autowired dependencies failed for class [" + clazz + "]", ex);}}
InjectionMetadata类包含要注入的元素的列表
注入是通过Java的API Reflection (Field set(Object obj, Object value) 或Method invoke(Object obj,Object … args)方法完成的
此过程直接在AutowiredAnnotationBeanPostProcessor的方法中调用public void processInjection(Object bean) throws BeanCreationException
它将所有可注入的bean检索为InjectionMetadata实例,并调用它们的inject()方法
public class InjectionMetadata {...
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()) {boolean debug = logger.isDebugEnabled();for (InjectedElement element : elementsToIterate) {if (debug) {logger.debug("Processing injected element of bean '" + beanName + "': " + element);}//看下面静态内部类的方法element.inject(target, beanName, pvs);}}}...public static abstract class InjectedElement {protected final Member member;protected final boolean isField;.../*** 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();}}}...}
}
findAutowiredAnnotation(AccessibleObject ao)
分析属于一个字段或一个方法的所有注解来查找@Autowired注解。如果未找到@Autowired注解,则返回null,字段或方法也就视为不可注入。

















