详解@ConfigurationProperties如何装载到Spring容器中

 更新时间:2023年07月30日 08:22:36   作者:JAVA旭阳  
这篇文章主要为大家详细介绍了@ConfigurationProperties该如何装载到Spring容器中,文中的示例代码讲解详细,需要的小伙伴可以参考一下

问题描述

最近项目中遇到了一个Spring@ConfigurationProperties注解的问题,如下:

1.定义了一个注解了@ConfigurationPropertiesUser Bean

@ConfigurationProperties(prefix = "my.user")
@Component
@Data
public class User {
    private String userName;
}

2.通过@Autowired使用UserBean,没有问题。

@RestController
@RequestMapping("/config")
@EnableConfigurationProperties(User.class)
public class UserConfigController {
    @Autowired
    private User user;
    @GetMapping("/username1")
    public String username1() {
        return user.getUserName();
    }
}

3.但是,有个同事修改了下变量名为user1,自信的以为没有问题,就提交测试了,然后直接报错了。

@RestController
@RequestMapping("/config")
@EnableConfigurationProperties(User.class)
public class UserConfigController {
    @Autowired
    private User user1;
    @GetMapping("/username2")
    public String username2() {
        return user1.getUserName();
    }
}

报错如下图所示:

这是怎么一回事呢,修改个变量名都能报错?

原因分析

根据报错信息不难分析出来主要原因在于User类在Spring容器中两个Bean对象,bean name分别是“user”和“my.user-com.alvinlkk.bean.User”。

使用@Autwired装配,实际上不只是根据类型装配,如果匹配到同类型有多个Bean对象,默认会去找和变量名“user”同名的Bean,所以不会报错。如果修改变量名改成user1, 它就匹配到两个Bean对象,然后用bean name=user1无法找到合适的,自然就报错了。

那么为什么会出现两个Bean呢?

1.因为使用@Component注解,创建了一个名称为“user”的Bean。

2.使用了@EnableConfigurationProperties注解创建了名称为my.user-com.alvinlkk.bean.User的Bean。

最佳实践

使用@ConfigurationProperties注解的Bean的时候,建议通过使用@EnableConfigurationProperties创建Bean。

源码解析

刨根问底,我们继续从Spring源码层面深入了解下这个问题的产生的根源。Spring创建Bean的过程其实很简单,大致分两个步骤:

  • 创建Bean的定义信息BeanDefinition,包含Bean的类型,名称等信息,注册到Bean定义工厂中。
  • 根据Bean定义工厂中的Bean定义信息,创建出Bean实例。

上面的两个过程中在通常在SpringBoot启动的过程中就完成,SpringBoot启动的时候,会调用容器的refresh(), 其中在invokeBeanFactoryPostProcessors(beanFactory)方法中创建并注册BeanDefinition, 在finishBeanFactoryInitialization()方法中创建Bean实例对象。

创建注册BeanDefinition

@Component注解

Compoent注解的的类会被Spring中的ConfigurationClassPostProcessor类处理,创建出对应的BeanDefinition,然后注册到BeanDefinitionRegistry中,具体流程如下图所示。

@Component注解的类User会被扫描到,生成一个名字是userBeanDefinition,然后注册到BeanDefitionRegistry中,如下图所示:

@EnableConfigurationProperties注解

注解@EnableConfigurationProperties源码中importEnableConfigurationPropertiesRegistrar类,那么它是在什么阶段创建出BeanDefinition呢?

最终配置了@EnableConfigurationProperties(User.class)中被获取,创建出name为my.user-com.alvinlkk.bean.UserBeanDefinition,如下图所示。

而且@Component的顺序是优先于@EnableConfigurationProperties的。

创建Bean对象

现在BeanDefinitionBean定义信息已经有了,Spring就可以根据这些信息创建出Bean对象实例了,这一个过程是在finishBeanFactoryInitialization()方法中进行的,我们这里重点关注下@Autowird方法是如何进行装配的。

  • AbstractApplicationContext#refresh(): 初始化容器
  • AbstractApplicationContext#finishBeanFactoryInitialization(): 初始化Bean入口
  • DefaultListableBeanFactory#preInstantiateSingletons():预先初始化单例Bean
  • DefaultListableBeanFactory#getBean(): 调用getBean()创建Bean实例
  • AbstractBeanFactory#doGetBean()getBean()最终调用的方法
  • AbstractAutowireCapableBeanFactory#createBean(): 创建Bean实例入口
  • DefaultListableBeanFactory#determineAutowireCandidate():选择使用哪个候选的Bean

根据类型匹配到Bean有多个的情况,会调用determineAutowireCandidate()方法进一步去根据name匹配bean。

总结

所以对于配置注解ConfigurationProperties的类不要使用使用@Component注解让Spring管理,更推荐的做法是使用@EnableConfigurationProperties注解进行装载。

以上就是详解@ConfigurationProperties如何装载到Spring容器中的详细内容,更多关于ConfigurationProperties装载到Spring容器的资料请关注脚本之家其它相关文章!

相关文章

  • Java中Builder模式的实现详解

    Java中Builder模式的实现详解

    在设计模式中对Builder模式的定义是用于构建复杂对象的一种模式,所构建的对象往往需要多步初始化或赋值才能完成。下面这篇文章主要给大家介绍了在Java各个版本中Builder模式实现的相关资料,文中介绍的非常详细,需要的朋友可以参考学习。
    2017-05-05
  • JAVA 8 ''::'' 关键字详解

    JAVA 8 ''::'' 关键字详解

    这篇文章主要介绍了JAVA 8 '::' 关键字,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-09-09
  • 解决SpringCloud Config结合github无法读取配置的问题

    解决SpringCloud Config结合github无法读取配置的问题

    这篇文章主要介绍了解决SpringCloud Config结合github无法读取配置的问题,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2021-02-02
  • Java 生成图片验证码3种方法(字母、加减乘除、中文)

    Java 生成图片验证码3种方法(字母、加减乘除、中文)

    这篇文章主要介绍了Java 生成图片验证码3种方法(字母、加减乘除、中文),文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-01-01
  • Java正确使用访问修饰符的姿势

    Java正确使用访问修饰符的姿势

    访问修饰符是Java语法中很基础的一部分,但是能正确的使用Java访问修饰符的程序员只在少数,下面这篇文章主要给大家介绍了关于Java正确使用访问修饰符的姿势,需要的朋友可以参考下
    2021-11-11
  • java音乐播放器课程设计

    java音乐播放器课程设计

    这篇文章主要为大家详细介绍了java音乐播放器的课程设计,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-06-06
  • mybatis-plus中BaseMapper入门使用

    mybatis-plus中BaseMapper入门使用

    本文主要介绍了mybatis-plus中BaseMapper入门使用,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-08-08
  • 深入了解Java数据结构和算法之堆

    深入了解Java数据结构和算法之堆

    这篇文章主要为大家介绍了Java数据结构和算法之堆 ,具有一定的参考价值,感兴趣的小伙伴们可以参考一下,希望能够给你带来帮助
    2022-01-01
  • JavaScript中HTML元素操作的实现

    JavaScript中HTML元素操作的实现

    本文主要介绍了JavaScript中HTML元素操作的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-06-06
  • java实现员工工资管理系统

    java实现员工工资管理系统

    这篇文章主要为大家详细介绍了java实现员工工资管理系统,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-02-02

最新评论