一文搞懂Spring @Autowired注解的使用及其原理

2024-03-07 1076阅读

温馨提示:这篇文章已超过387天没有更新,请注意相关的内容是否还可用!

一、全文概览

依赖注入(DI)是Spring核心特性之一,而@Autowired也是我们日常高频使用的Spring依赖注入方式之一,因此有必要对它的使用以及原理做一个全面的掌握。本文从@Autowired使用、原理入手记录,并扩展延伸Spring中其他具备注入功能的注解。

一文搞懂Spring @Autowired注解的使用及其原理

二、@Autowired简介与使用

1、简介

我们直接通Autowired注解源码来看下该注解的简介

// 可以标注在构造器、方法、参数、字段、注解类型(做为元注解)上
@Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD, ElementType.ANNOTATION_TYPE})
// 运行时注解
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Autowired {
	/**
	 * Declares whether the annotated dependency is required.
	 * 声明该注解标注的依赖是否需要一定存在于Spring容器中
	 * 				true为必须存在,如果不存在的话就抛出NoSuchBeanDefinitionException异常
	 *				false不要求必须存在,如果不存在也不抛出异常(一般不建议设置,可能会引发线上事故)
	 * 

Defaults to {@code true}. */ boolean required() default true; }

通过上面代码我们可以看出@Autowired可以标注在构造器、方法、参数、字段以及派生注解上,所以注入时机非常多,可以准确的控制在何时、何处注入以及如何注入。

2、使用

我们先来学习下关于@Autowired的使用方式:

Bean配置类

public class BeanConfiguration {
    @Bean
    public User user() {
        return new User("markus", 24);
    }
}

演示类

package com.markus.spring.injection;
import com.markus.spring.annotation.MyAutowired;
import com.markus.spring.bean.User;
import com.markus.spring.configuration.BeanConfiguration;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Import;
import java.util.Collection;
import java.util.Map;
/**
 * @author: markus
 * @date: 2023/2/5 10:43 PM
 * @Description: @Autowired注解示例
 * @Blog: https://markuszhang.com
 * It's my honor to share what I've learned with you!
 */
// 导入Bean配置
@Import({
        com.markus.spring.configuration.BeanConfiguration.class
})
public class AutowiredAnnotationDependencyInjectionDemo {
    @Autowired
    private User user;
    @Autowired
    private Map userMap;
    @Autowired
    private Collection userCollection;
    private User userFromCtor;
    //    @Autowired 可标注在构造器或者构造器的参数里面,两者取其一即可
    public AutowiredAnnotationDependencyInjectionDemo(@Autowired User user) {
        this.userFromCtor = user;
    }
    private User userFromMethod;
    @Autowired
    public void autowiredUser(User user) {
        this.userFromMethod = user;
    }
    @MyAutowired
    private User userFromCustomAnnotation;
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
        context.register(AutowiredAnnotationDependencyInjectionDemo.class);
        context.refresh();
        AutowiredAnnotationDependencyInjectionDemo demo = context.getBean(AutowiredAnnotationDependencyInjectionDemo.class);
        System.out.println("demo.user : " + demo.user);
        System.out.println("demo.userMap : " +demo.userMap);
        System.out.println("demo.userCollection : " +demo.userCollection);
        System.out.println("demo.userFromCtor : " +demo.userFromCtor);
        System.out.println("demo.userFromMethod : " +demo.userFromMethod);
        System.out.println("demo.userFromCustomAnnotation : " +demo.userFromCustomAnnotation);
        context.close();
    }
}

控制台结果

一文搞懂Spring @Autowired注解的使用及其原理

当Spring容器中有多个相同类型的Bean时,它还可以与@Qualifier配合使用来指定某一特定的Bean

Bean配置

/**
 * @author: markus
 * @date: 2023/2/11 4:49 PM
 * @Description: 相同类型多个Bean配置
 * @Blog: https://markuszhang.com
 * It's my honor to share what I've learned with you!
 */
public class SameTypeBeanConfiguration {
    @Bean
    public User user1() {
        return new User("markus", 24);
    }
    @Bean
    public User user2() {
        return new User("Luna", 23);
    }
}

演示类

package com.markus.spring.injection;
import com.markus.spring.bean.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Import;
/**
 * @author: markus
 * @date: 2023/2/11 4:47 PM
 * @Description:
 * @Blog: https://markuszhang.com
 * It's my honor to share what I've learned with you!
 */
@Import({
        com.markus.spring.configuration.SameTypeBeanConfiguration.class
})
public class QualifierAnnotationUseDemo {
    @Autowired
    @Qualifier(value = "user1")
    private User user;
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
        context.register(QualifierAnnotationUseDemo.class);
        context.refresh();
        QualifierAnnotationUseDemo demo = context.getBean(QualifierAnnotationUseDemo.class);
        System.out.println("demo.user : " + demo.user);
        context.close();
    }
}

控制台

一文搞懂Spring @Autowired注解的使用及其原理

三、@Autowired原理

1、Bean的生命周期

在讲解@Autowired原理之前,有必要先提及一下Bean的生命周期,但在这里不做过多叙述,只是让大家有个大致的认识,以及@Autowired在哪里开始发挥作用的。

一文搞懂Spring @Autowired注解的使用及其原理

上图为Spring Bean的整个的一个生命周期,包括定义Bean配置信息、加载解析并注册Bean元信息,在我们程序运行时getBean获取Spring Bean又会经过Bean的实例化、属性赋值、初始化等环节,在这些环节前后,Spring也给了我们一些扩展机会,例如实例化前后、属性赋值前、初始化前、初始化后。因为Spring 单例Bean的生命周期是交给容器去管理的,所以Bean的销毁最后也依赖于容器的销毁,当容器发出销毁消息时,会触发Bean的销毁逻辑,这是我们也可以在Bean销毁前做一些自定义操作。至此就是关于Spring Bean生命周期的一个大体介绍。

那么@Autowired到底发生在哪个阶段呢?我们接下来再来分析下BeanFactory#getBean的内部大致流程!

一文搞懂Spring @Autowired注解的使用及其原理

上图中标红的备注中正是@Autowired发挥作用的环节。Bean生命周期后续会单独写一篇文章,这里就不做展开了,我们把关注点聚焦到@Autowired实现细节上去!

2、@Autowired实现细节

通过Bean生命周期概览,我们知道如果想要挖掘@Autowired实现的原理,我们先要去了解两个类:

  • AbstractAutowiredCapableBeanFactory
  • AutowiredAnnotationBeanPostProcessor
    1、AbstractAutowiredCapableBeanFactory

    我们通过IDEA定位到AbstractAutowiredCapableBeanFactory这个类的doCreateBean方法,在这个方法里面我们关注两个函数:

    • applyMergerBeanDefinitionPostProcessors 它是spring提供给用户or框架内部的有关post-processors去修改合并BeanDefinition的机会
    • populateBean 它是spring给bean进行属性赋值的函数入口
      protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
      			throws BeanCreationException {
        // Allow post-processors to modify the merged bean definition.
        synchronized (mbd.postProcessingLock) {
          if (!mbd.postProcessed) {
            try {
              applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
            }
            catch (Throwable ex) {
              // xxx
          }
        }
        try {
          populateBean(beanName, mbd, instanceWrapper);
        }
        catch (Throwable ex) {
          // xxx
        }
        return exposedObject;
      }
      

      通过doCreateBean函数进入到applyMergedBeanDefinitionPostProcessors方法,来看看其内部做了哪些事情:

      • 它其实就做了一件事:拿到容器中的BeanPostProcessor集合并遍历,寻找属于MergedBeanDefinitionPostProcessor的BeanPostProcessor,并执行bdp.postProcessorMergedBeanDefinition后置处理方法
      • AutowiredAnnotationBeanPostProcessor正是MergedBeanDefinitionPostProcessor的一个派生子类,稍后我们介绍该类的时候提及这个方法的细节
        protected void applyMergedBeanDefinitionPostProcessors(RootBeanDefinition mbd, Class beanType, String beanName) {
          for (BeanPostProcessor bp : getBeanPostProcessors()) {
            if (bp instanceof MergedBeanDefinitionPostProcessor) {
              MergedBeanDefinitionPostProcessor bdp = (MergedBeanDefinitionPostProcessor) bp;
              bdp.postProcessMergedBeanDefinition(mbd, beanType, beanName);
            }
          }
        }
        

        返回到doCreateBean函数并进入到populateBean方法,抛出非核心的代码逻辑,我们可以看到该函数内部一共有四大核心逻辑处理:

        • 获取InstantiationAwareBeanPostProcessor集合并遍历执行其PostProcessAfterInstantiation后处理方法,意在执行bean实例化后、属性赋值前的一些扩展逻辑
        • 解析bean元信息配置的依赖注入模型mbd.getResolvedAutowireMode,这里通常是有xml bean配置的autowire指定
          • 这里处理byName和byType,constructor是通过实例创建的时候被处理的
          • 获取InstantiationAwareBeanPostProcessor集合并遍历执行其postProcessProperties方法,这里也就是@Autowired注解进行依赖注入的时机,在AutowiredAnnotationBeanPostProcessor我们会提及这个方法的细节
          • 最后将PropertyValues的内容注入到最终的Bean实例相应的字段中(这块用于xml配置的字段设置)
            protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
              // Give any InstantiationAwareBeanPostProcessors the opportunity to modify the
              // state of the bean before properties are set. This can be used, for example,
              // to support styles of field injection.
              if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
                for (BeanPostProcessor bp : getBeanPostProcessors()) {
                  if (bp instanceof InstantiationAwareBeanPostProcessor) {
                    InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
                    if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
                      return;
                    }
                  }
                }
              }
              PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);
              int resolvedAutowireMode = mbd.getResolvedAutowireMode();
              if (resolvedAutowireMode == AUTOWIRE_BY_NAME || resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
                MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
                // Add property values based on autowire by name if applicable.
                if (resolvedAutowireMode == AUTOWIRE_BY_NAME) {
                  autowireByName(beanName, mbd, bw, newPvs);
                }
                // Add property values based on autowire by type if applicable.
                if (resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
                  autowireByType(beanName, mbd, bw, newPvs);
                }
                pvs = newPvs;
              }
              boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
              boolean needsDepCheck = (mbd.getDependencyCheck() != AbstractBeanDefinition.DEPENDENCY_CHECK_NONE);
              PropertyDescriptor[] filteredPds = null;
              if (hasInstAwareBpps) {
                if (pvs == null) {
                  pvs = mbd.getPropertyValues();
                }
                for (BeanPostProcessor bp : getBeanPostProcessors()) {
                  if (bp instanceof InstantiationAwareBeanPostProcessor) {
                    InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
                    PropertyValues pvsToUse = ibp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
                    pvs = pvsToUse;
                  }
                }
              }
              if (pvs != null) {
                applyPropertyValues(beanName, mbd, bw, pvs);
              }
            }
            
            2、AutowiredAnnotationBeanPostProcessor

            通过Bean生命周期概览,我们可以知道@Autowired是在Bean属性赋值阶段将依赖Bean注入到当前Bean字段中的,实现类是AutowiredAnnotationBeanPostProcessor,我们先来了解下它的继承结构并解释它的相关功能

            一文搞懂Spring @Autowired注解的使用及其原理

            看到上图的继承结构可以发现其实AutowiredAnnotationBeanPostProcessor具备两方面的功能,一方面是InstantiationAwareBeanPostProcessor在Bean实例化前后以及属性赋值前做些扩展;另一方面是在合并BeanDefinition后做些扩展,所谓“合并BeanDefinition”就是将配置的子BeanDefinition和父BeanDefinition合并形成当前Bean的最终BeanDefinition配置元信息,这里给大家举个具体例子:

            
                
                
                
                
                
                
            
            
            
                
            
            
            

            我们先来看下AutowiredAnnotationBeanPostProcessor的构造器,可以看出它是@Autowired、@Value以及jsr-330的@Inject注解的实现,我们本节主要分析@Autowired注解的实现原理。

            public AutowiredAnnotationBeanPostProcessor() {
              this.autowiredAnnotationTypes.add(Autowired.class);
              this.autowiredAnnotationTypes.add(Value.class);
              try {
                this.autowiredAnnotationTypes.add((Class
VPS购买请点击我

免责声明:我们致力于保护作者版权,注重分享,被刊用文章因无法核实真实出处,未能及时与作者取得联系,或有版权异议的,请联系管理员,我们会立即处理! 部分文章是来自自研大数据AI进行生成,内容摘自(百度百科,百度知道,头条百科,中国民法典,刑法,牛津词典,新华词典,汉语词典,国家院校,科普平台)等数据,内容仅供学习参考,不准确地方联系删除处理! 图片声明:本站部分配图来自人工智能系统AI生成,觅知网授权图片,PxHere摄影无版权图库和百度,360,搜狗等多加搜索引擎自动关键词搜索配图,如有侵权的图片,请第一时间联系我们,邮箱:ciyunidc@ciyunshuju.com。本站只作为美观性配图使用,无任何非法侵犯第三方意图,一切解释权归图片著作权方,本站不承担任何责任。如有恶意碰瓷者,必当奉陪到底严惩不贷!

目录[+]