热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

SpringBoot中@Autowired生效方式详解

@Autowired注解可以用在类属性,构造函数,setter方法和函数参数上,该注解可以准确地控制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 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 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)
                                            ((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 elements = new ArrayList<>();
        Class targetClass = clazz;
        do {
            final List 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)
                    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内容请搜索以前的文章或继续浏览下面的相关文章希望大家以后多多支持!


推荐阅读
  • r2dbc配置多数据源
    R2dbc配置多数据源问题根据官网配置r2dbc连接mysql多数据源所遇到的问题pom配置可以参考官网,不过我这样配置会报错我并没有这样配置将以下内容添加到pom.xml文件d ... [详细]
  • 本文讨论了在Spring 3.1中,数据源未能自动连接到@Configuration类的错误原因,并提供了解决方法。作者发现了错误的原因,并在代码中手动定义了PersistenceAnnotationBeanPostProcessor。作者删除了该定义后,问题得到解决。此外,作者还指出了默认的PersistenceAnnotationBeanPostProcessor的注册方式,并提供了自定义该bean定义的方法。 ... [详细]
  • Spring常用注解(绝对经典),全靠这份Java知识点PDF大全
    本文介绍了Spring常用注解和注入bean的注解,包括@Bean、@Autowired、@Inject等,同时提供了一个Java知识点PDF大全的资源链接。其中详细介绍了ColorFactoryBean的使用,以及@Autowired和@Inject的区别和用法。此外,还提到了@Required属性的配置和使用。 ... [详细]
  • 基于PgpoolII的PostgreSQL集群安装与配置教程
    本文介绍了基于PgpoolII的PostgreSQL集群的安装与配置教程。Pgpool-II是一个位于PostgreSQL服务器和PostgreSQL数据库客户端之间的中间件,提供了连接池、复制、负载均衡、缓存、看门狗、限制链接等功能,可以用于搭建高可用的PostgreSQL集群。文章详细介绍了通过yum安装Pgpool-II的步骤,并提供了相关的官方参考地址。 ... [详细]
  • 本文介绍了Oracle数据库中tnsnames.ora文件的作用和配置方法。tnsnames.ora文件在数据库启动过程中会被读取,用于解析LOCAL_LISTENER,并且与侦听无关。文章还提供了配置LOCAL_LISTENER和1522端口的示例,并展示了listener.ora文件的内容。 ... [详细]
  • 本文介绍了多因子选股模型在实际中的构建步骤,包括风险源分析、因子筛选和体系构建,并进行了模拟实证回测。在风险源分析中,从宏观、行业、公司和特殊因素四个角度分析了影响资产价格的因素。具体包括宏观经济运行和宏经济政策对证券市场的影响,以及行业类型、行业生命周期和行业政策对股票价格的影响。 ... [详细]
  • http:my.oschina.netleejun2005blog136820刚看到群里又有同学在说HTTP协议下的Get请求参数长度是有大小限制的,最大不能超过XX ... [详细]
  • 本文讨论了在openwrt-17.01版本中,mt7628设备上初始化启动时eth0的mac地址总是随机生成的问题。每次随机生成的eth0的mac地址都会写到/sys/class/net/eth0/address目录下,而openwrt-17.01原版的SDK会根据随机生成的eth0的mac地址再生成eth0.1、eth0.2等,生成后的mac地址会保存在/etc/config/network下。 ... [详细]
  • SpringBoot整合SpringSecurity+JWT实现单点登录
    SpringBoot整合SpringSecurity+JWT实现单点登录,Go语言社区,Golang程序员人脉社 ... [详细]
  • Centos7搭建ELK(Elasticsearch、Logstash、Kibana)教程及注意事项
    本文介绍了在Centos7上搭建ELK(Elasticsearch、Logstash、Kibana)的详细步骤,包括下载安装包、安装Elasticsearch、创建用户、修改配置文件等。同时提供了使用华为镜像站下载安装包的方法,并强调了保证版本一致的重要性。 ... [详细]
  • 解决nginx启动报错epoll_wait() reported that client prematurely closed connection的方法
    本文介绍了解决nginx启动报错epoll_wait() reported that client prematurely closed connection的方法,包括检查location配置是否正确、pass_proxy是否需要加“/”等。同时,还介绍了修改nginx的error.log日志级别为debug,以便查看详细日志信息。 ... [详细]
  • 重入锁(ReentrantLock)学习及实现原理
    本文介绍了重入锁(ReentrantLock)的学习及实现原理。在学习synchronized的基础上,重入锁提供了更多的灵活性和功能。文章详细介绍了重入锁的特性、使用方法和实现原理,并提供了类图和测试代码供读者参考。重入锁支持重入和公平与非公平两种实现方式,通过对比和分析,读者可以更好地理解和应用重入锁。 ... [详细]
  • NotSupportedException无法将类型“System.DateTime”强制转换为类型“System.Object”
    本文介绍了在使用LINQ to Entities时出现的NotSupportedException异常,该异常是由于无法将类型“System.DateTime”强制转换为类型“System.Object”所导致的。同时还介绍了相关的错误信息和解决方法。 ... [详细]
  • 本文介绍了Java集合库的使用方法,包括如何方便地重复使用集合以及下溯造型的应用。通过使用集合库,可以方便地取用各种集合,并将其插入到自己的程序中。为了使集合能够重复使用,Java提供了一种通用类型,即Object类型。通过添加指向集合的对象句柄,可以实现对集合的重复使用。然而,由于集合只能容纳Object类型,当向集合中添加对象句柄时,会丢失其身份或标识信息。为了恢复其本来面貌,可以使用下溯造型。本文还介绍了Java 1.2集合库的特点和优势。 ... [详细]
  • 本文介绍了在go语言中利用(*interface{})(nil)传递参数类型的原理及应用。通过分析Martini框架中的injector类型的声明,解释了values映射表的作用以及parent Injector的含义。同时,讨论了该技术在实际开发中的应用场景。 ... [详细]
author-avatar
他像强盗霸占了d我的心
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有