SpringBoot中@Autowired生效方式详解

目录
  • 前言
  • 正文
    • 注册AutowiredProcessor的BeanDefinition
    • 实例化AutowiredProcessor
    • 创建bean时进行注入
  • 后记

前言

@Component
public class SimpleBean3 {
    @Autowired
    private SimpleBean simpleBean;
}

@Autowired修饰的字段会被容器自动注入.那么Spring Boot中使如何实现这一功能呢? AutowiredAnnotationBeanPostProcessor!

BeanPostProcessor implementation that autowires annotated fields, setter methods, and arbitrary config methods. Such members to be injected are detected through annotations: by default, Spring's @Autowired and @Value annotations.
Also supports JSR-330's @Inject annotation, if available, as a direct alternative to Spring's own @Autowired.

AutowiredAnnotationBeanPostProcessor(以下简称AutowiredProcessor)间接实现了InstantiationAwareBeanPostProcessor接口.通过postProcessProperties(...)完成@Autowired的注入,本文将按照下图流程梳理AutowiredProcessor的生效逻辑.

SpringBoot-autowired.png

正文

注册AutowiredProcessor的BeanDefinition

SpringApplication#createApplicationContext默认会创建 AnnotationConfigApplicationContext,而AnnotationConfigApplicationContext又会创建AnnotatedBeanDefinitionReader

    public AnnotationConfigApplicationContext() {
        this.reader = new AnnotatedBeanDefinitionReader(this);
        this.scanner = new ClassPathBeanDefinitionScanner(this);
    }

AnnotatedBeanDefinitionReader构造时会调用AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry),将AutowiredProcessor的BeanDefinition注册到容器

    public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(
            BeanDefinitionRegistry registry, @Nullable Object source) {
        //忽略部分代码...
        if (!registry.containsBeanDefinition(AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) {
            RootBeanDefinition def = new RootBeanDefinition(AutowiredAnnotationBeanPostProcessor.class);
            def.setSource(source);
            beanDefs.add(registerPostProcessor(registry, def, AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME));
        }
        //忽略部分代码...
        return beanDefs;
    }

实例化AutowiredProcessor

在AbstractApplicationContext的refresh阶段,会注册并实例化所有的BeanPostProcessor

public void refresh() throws BeansException, IllegalStateException {
            //...忽略部分代码
                // Allows post-processing of the bean factory in context subclasses.
                postProcessBeanFactory(beanFactory);
                // Invoke factory processors registered as beans in the context.
                invokeBeanFactoryPostProcessors(beanFactory);
                // ########### 这里注册所有的BeanPostProcessor ##########
                // Register bean processors that intercept bean creation.
                registerBeanPostProcessors(beanFactory);
                // Initialize message source for this context.
                initMessageSource();
                // Initialize event multicaster for this context.
                initApplicationEventMulticaster();
                // Initialize other special beans in specific context subclasses.
                onRefresh();
                // Check for listener beans and register them.
                registerListeners();
                // Instantiate all remaining (non-lazy-init) singletons.
                finishBeanFactoryInitialization(beanFactory);
                // Last step: publish corresponding event.
                finishRefresh()
            //...忽略部分代码
    }

实际的注册逻辑交给了PostProcessorRegistrationDelegate

    protected void registerBeanPostProcessors(ConfigurableListableBeanFactory beanFactory) {
        PostProcessorRegistrationDelegate.registerBeanPostProcessors(beanFactory, this);
    }

在PostProcessorRegistrationDelegate中,获取到所有的BeanPostProcessor(基于BeanDefinition),并将其分为几种类型,并按照不同的优先级进行处理化,这块不是这篇文章的重点,我们只需要知道在这里AutowiredProcessor被注册就可以了.

创建bean时进行注入

以SimpleBean3的注入为例, 它是单例的,在AbstractApplicationContext.refresh()的finishBeanFactoryInitialization(beanFactory)时创建.

    protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
        //...忽略部分代码
        // Instantiate all remaining (non-lazy-init) singletons.
        beanFactory.preInstantiateSingletons();
    }

调用到了BeanFactory.preInstantiateSingletons(),走到getBean()逻辑

public void preInstantiateSingletons() throws BeansException {
        //...忽略部分代码
        List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);
        // Trigger initialization of all non-lazy singleton beans...
        for (String beanName : beanNames) {
            RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
            if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
                if (isFactoryBean(beanName)) {
                    Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
                    if (bean instanceof FactoryBean) {
                        final FactoryBean<?> factory = (FactoryBean<?>) bean;
                        boolean isEagerInit;
                        if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
                            isEagerInit = AccessController.doPrivileged((PrivilegedAction<Boolean>)
                                            ((SmartFactoryBean<?>) factory)::isEagerInit,
                                    getAccessControlContext());
                        }
                        else {
                            isEagerInit = (factory instanceof SmartFactoryBean &&
                                    ((SmartFactoryBean<?>) factory).isEagerInit());
                        }
                        if (isEagerInit) {
                            getBean(beanName);
                        }
                    }
                }
                else {
                    getBean(beanName);
                }
            }
        }
        //...忽略部分代码
    }

经过一连串的辗转,最终调用到AbstractAutowireCapableBeanFactory#populateBean

附上调用链路

image.png

在populateBean中,会将所有的BeanPostProcessor应用在这个bean上,包括AutowiredProcessor

protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
        //...忽略部分代码
        PropertyDescriptor[] filteredPds = null;
        if (hasInstAwareBpps) {
            if (pvs == null) {
                pvs = mbd.getPropertyValues();
            }
            for (BeanPostProcessor bp : getBeanPostProcessors()) {
                if (bp instanceof InstantiationAwareBeanPostProcessor) {
                    InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
          //###### 调用到postProcessProperties #####
                    PropertyValues pvsToUse = ibp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
                    if (pvsToUse == null) {
                        if (filteredPds == null) {
                            filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
                        }
                        pvsToUse = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
                        if (pvsToUse == null) {
                            return;
                        }
                    }
                    pvs = pvsToUse;
                }
            }
        }
    //...忽略部分代码
    }

AutowiredProcessor的postProcessProperties()会进行注入操作,这需要找到注入的元数据(InjectionMetadata)

public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
        //### 找到AutowringMetadata #####
        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;
    }

findAutowiringMetadata()又调用到buildAutowiringMetadata(),生成代表可注入元素的InjectMetadata

private InjectionMetadata buildAutowiringMetadata(final Class<?> clazz) {
        List<InjectionMetadata.InjectedElement> elements = new ArrayList<>();
        Class<?> targetClass = clazz;
        do {
            final List<InjectionMetadata.InjectedElement> currElements = new ArrayList<>();
            ReflectionUtils.doWithLocalFields(targetClass, field -> {
        //###### 找到带有可注入注解的字段
                AnnotationAttributes 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));
                }
            });
            //...忽略部分代码
    }

findAutowiredAnnotation()根据AutowiredProcessor的实例字段autowiredAnnotationTypes,去查看是否匹配,这个字段是在AutowiredProcessor创建时初始化,可以看到支持@Autowired,@Value,@Inject三种类型的注入标识.最终据此完成注入

public AutowiredAnnotationBeanPostProcessor() {
        this.autowiredAnnotationTypes.add(Autowired.class);
        this.autowiredAnnotationTypes.add(Value.class);
        try {
            this.autowiredAnnotationTypes.add((Class&lt;? extends Annotation&gt;)
                    ClassUtils.forName("javax.inject.Inject", AutowiredAnnotationBeanPostProcessor.class.getClassLoader()));
            logger.trace("JSR-330 'javax.inject.Inject' annotation found and supported for autowiring");
        }
        catch (ClassNotFoundException ex) {
            // JSR-330 API not available - simply skip.
        }
    }

后记

最后再来梳理一下整个流程.

首先是AutowiredPorcessor的BeanDefinition的注册

=> 创建ApplicationContext

​ => 创建AnnotatedBeanDefinitionReader

​ => 注册BeanDefinition registerAnnotationConfigProcessors

然后是AutowiredProcessor注册为bean

=> registerBeanPostProcessors

最后是注入

​ => 获取bean getBean()

​ => 创建bean doCreateBean()

​ =>生成bean populateBean()

​ => 应用AutowiredProcessor ibp.postProcessProperties()

​ => 找到可注入的字段 buildAutowiringMetadata

​ => 注入 metadata.inject

至此,@Autowired生效逻辑梳理完成

到此这篇关于SpringBoot中@Autowired生效方式详解的文章就介绍到这了,更多相关SpringBoot @Autowired内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • SpringBoot使用@Autowired为多实现的接口注入依赖

    目录 使用@Autowired为多实现的接口注入依赖 问题描述 方法一:使用@Qualifier限定 方法二:利用@Autowired可以byName匹配Bean的特性 方法三:使用@Primay 一个接口多个实现类的Spring注入 1. 首先, Interface1 接口有两个实现类 2. 通过 @Autowired 和 @Qualifier 配合注入 3. 使用@Resource注入,根据默认类名区分 4. 使用@Resource注入,根据@Service指定的名称区分 使用@Autowi

  • 详解SpringBoot 多线程处理任务 无法@Autowired注入bean问题解决

    在多线程处理问题时,无法通过@Autowired注入bean,报空指针异常, 在线程中为了线程安全,是防注入的,如果要用到这个类,只能从bean工厂里拿个实例. 解决方法如下: 1.创建一个工具类代码: package com.hqgd.pms.common; import org.springframework.beans.BeansException; import org.springframework.context.ApplicationContext; import org.spri

  • 解决Springboot @Autowired 无法注入问题

    特别提醒:一定要注意文件结构 WebappApplication 一定要在包的最外层,否则Spring无法对所有的类进行托管,会造成@Autowired 无法注入. 1. 添加工具类获取在 Spring 中托管的 Bean (1)工具类 package com.common; import org.springframework.beans.BeansException; import org.springframework.beans.factory.NoSuchBeanDefinitionE

  • springBoot Junit测试用例出现@Autowired不生效的解决

    目录 springBoot Junit测试用例出现@Autowired不生效 1,测试类上面添加支持的注解 2,出现错误 3,注解解释 4,junit测试如何在idea上通过类中方法直接生成测试用例 第一步 第二步 第三步 Junit中@Autowired失效 原因 解决方案 springBoot Junit测试用例出现@Autowired不生效 前提条件: 1,测试类上面添加支持的注解 就能取到spring中的容器的实例,如果配置了@Autowired那么就自动将对象注入. @RunWith(

  • 浅谈SpringBoot @Autowired的两种注入方式

    Autowired有两种注入方式 by type by name 默认使用的是byType的方式向Bean里面注入相应的Bean.例如: @Autowired private UserService userService; 这段代码会在初始化的时候,在spring容器中寻找一个类型为UserService的bean实体注入,关联到userService的引入上. 但是如果UserService这个接口存在多个实现类的时候,就会在spring注入的时候报错,例如: public class Us

  • SpringBoot @Autowired注解注入规则介绍

    目录 @Autowired注解注入规则 验证 小结一下 @Autowired注解无法自动注入的错误 @Autowired注解注入规则 @Autowired - 注入默认根据类型,匹配不到则根据bean名字 Spring中注解方式的默认beanName生成规则: 在Spring中,当我们配置一个bean的时候,可以不指定name,这样的话,Spring会生成一个默认的beanName 1. 驼峰形式类名首字母小写:UserService--userService 2. 特殊情况--当类名的首字母和

  • 解决SpringBoot项目使用多线程处理任务时无法通过@Autowired注入bean问题

    最近在做一个"温湿度控制"的项目,项目要求通过用户设定的温湿度数值和实时采集到的数值进行比对分析,因为数据的对比与分析是一个通过前端页面控制的定时任务,经理要求在用户开启定时任务时,单独开启一个线程进行数据的对比分析,并将采集到的温湿度数值存入数据库中的历史数据表,按照我们正常的逻辑应该是用户在请求开启定时任务时,前端页面通过调用后端接口,创建一个新的线程来执行定时任务,然后在线程类中使用 @Autowired 注解注入保存历史数据的service层,在线程类中调用service层保存

  • 解决SpringBoot 测试类无法自动注入@Autowired的问题

    原来的测试类的注解: @RunWith(SpringRunner.class) @SpringBootTest 一直没法自动注入,后来在@SpringBootTest, 加入启动类Application后就可以了 @RunWith(SpringRunner.class) @SpringBootTest(classes = Application.class) 补充:spring boot项目单元测试时,@Autowired无法注入Service解决方式 首先确认: 测试类所在包名要和启动类一致

  • springboot 静态方法中使用@Autowired注入方式

    目录 静态方法使用@Autowired注入 静态方法使用@Autowired注入的类 解决方法 静态方法使用@Autowired注入 @Component public class StructUtil { private static StructService structService; private static List<StructInfo> structInfos; // 通过重写set注入 @Autowired public void setStructService(Str

  • SpringBoot中@Autowired生效方式详解

    目录 前言 正文 注册AutowiredProcessor的BeanDefinition 实例化AutowiredProcessor 创建bean时进行注入 后记 前言 @Component public class SimpleBean3 { @Autowired private SimpleBean simpleBean; } @Autowired修饰的字段会被容器自动注入.那么Spring Boot中使如何实现这一功能呢? AutowiredAnnotationBeanPostProces

  • 分析Springboot中嵌套事务失效原因详解

    首先两个事务方法,其中一个调用另一个. @Transactional(rollbackFor = Exception.class) public void trance() { try { trance1();//调用下一个事务方法. } catch (Exception e) { e.printStackTrace(); } User user = new User(); ShardingIDConfig shardingIDConfig = new ShardingIDConfig(); u

  • springboot中filter的用法详解

    一.在spring的应用中我们存在两种过滤的用法,一种是拦截器.另外一种当然是过滤器.我们这里介绍过滤器在springboot的用法,在springmvc中的用法基本上一样,只是配置上面有点区别. 二.filter功能,它使用户可以改变一个 request和修改一个response. Filter 不是一个servlet,它不能产生一个response,它能够在一个request到达servlet之前预处理request,也可以在离开 servlet时处理response.换种说法,filter

  • Linux下Docker CE使用从包中安装的方式详解

    使用从包中安装的方式,在Linux上安装Docker CE 1.查看Linux系统信息nuame -a 我的是Debian, amd64 2.查看Linux 系统发行版的名称 lsb_release -cs 我的是stretch 3.进入到下载包页面https://download.docker.com/linux/ 第一步获取的Debian,点击进入debian>dists 进入了这个连接地址 https://download.docker.com/linux/debian/dists/ 第二

  • 深入C/C++浮点数在内存中的存储方式详解

    任何数据在内存中都是以二进制的形式存储的,例如一个short型数据1156,其二进制表示形式为00000100 10000100.则在Intel CPU架构的系统中,存放方式为  10000100(低地址单元) 00000100(高地址单元),因为Intel CPU的架构是小端模式.但是对于浮点数在内存是如何存储的?目前所有的C/C++编译器都是采用IEEE所制定的标准浮点格式,即二进制科学表示法.在二进制科学表示法中,S=M*2^N 主要由三部分构成:符号位+阶码(N)+尾数(M).对于flo

  • springboot中thymeleaf模板使用详解

    这篇文章将更加全面详细的介绍thymeleaf的使用.thymeleaf 是新一代的模板引擎,在spring4.0中推荐使用thymeleaf来做前端模版引擎. thymeleaf介绍 简单说, Thymeleaf 是一个跟 Velocity.FreeMarker 类似的模板引擎,它可以完全替代 JSP .相较与其他的模板引擎,它有如下三个极吸引人的特点: 1.Thymeleaf 在有网络和无网络的环境下皆可运行,即它可以让美工在浏览器查看页面的静态效果,也可以让程序员在服务器查看带数据的动态页

  • Springboot中@Value的使用详解

    Springboot通过@Value注解将配置文件中的属性注入到容器内组件中(可用在@Controller.@Service.@Configuration.@Component等Spring托管的类中) 1.普通字符串注入 例:yml中存在key: name: zs @Value注入 @Value("${name}") public String name; 当yml中的name没有对应值时,即yml中为: name: 此时字符串name的值为"" 可设置注入属性的

  • SpringBoot中@ComponentScan的使用详解

    目录 SpringBoot @ComponentScan的使用 SpringBoot @ComponentScan 作用 SpringBoot @ComponentScan的使用 SpringBoot的启动类中有一个@ComponentScan,之前项目由于这个注解造成打包失败,这里对于这个注解进行总结,防止下次遇到这个问题再被难住. 其实这个注解主要是针对于第三方jar包中注解的应用. 如果第三方包中没有使用注解那么就完全不需要使用这个注解 使用方式如图所示,这里扫描的是 maven项目的依赖

  • JavaScript中的继承方式详解

    js继承的概念 js里常用的如下两种继承方式: 原型链继承(对象间的继承) 类式继承(构造函数间的继承) 由于js不像java那样是真正面向对象的语言,js是基于对象的,它没有类的概念.所以,要想实现继承,可以用js的原型prototype机制或者用apply和call方法去实现 在面向对象的语言中,我们使用类来创建一个自定义对象.然而js中所有事物都是对象,那么用什么办法来创建自定义对象呢?这就需要用到js的原型: 我们可以简单的把prototype看做是一个模版,新创建的自定义对象都是这个模

  • Docker容器跨主机通信中直接路由方式详解

    概述 就目前Docker自身默认的网络来说,单台主机上的不同Docker容器可以借助docker0网桥直接通信,这没毛病,而不同主机上的Docker容器之间只能通过在主机上用映射端口的方法来进行通信,有时这种方式会很不方便,甚至达不到我们的要求,因此位于不同物理机上的Docker容器之间直接使用本身的IP地址进行通信很有必要.再者说,如果将Docker容器起在不同的物理主机上,我们不可避免的会遭遇到Docker容器的跨主机通信问题.本文就来尝试一下. 方案原理分析 由于使用容器的IP进行路由,就

随机推荐