最近项目中遇到了一个Spring中@ConfigurationProperties注解的容器问题,如下:
@ConfigurationProperties(prefix = "my.user")@Component@Datapublic class User { private String userName;}
@RestController@RequestMapping("/config")@EnableConfigurationProperties(User.class)public class UserConfigController { @Autowired private User user; @GetMapping("/username1") public String username1() { return user.getUserName(); }}
图片
@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呢?
图片
最佳实践
使用@ConfigurationProperties注解的Bean的时候,建议通过使用@EnableConfigurationProperties创建Bean。
刨根问底,我们继续从Spring源码层面深入了解下这个问题的产生的根源。Spring创建Bean的过程其实很简单,大致分两个步骤:
上面的两个过程中在通常在SpringBoot启动的过程中就完成,SpringBoot启动的时候,会调用容器的refresh(), 其中在invokeBeanFactoryPostProcessors(beanFactory)方法中创建并注册BeanDefinition, 在finishBeanFactoryInitialization()方法中创建Bean实例对象。
图片
被Compoent注解的的类会被Spring中的ConfigurationClassPostProcessor类处理,创建出对应的BeanDefinition,然后注册到BeanDefinitionRegistry中,具体流程如下图所示。
图片
被@Component注解的类User会被扫描到,生成一个名字是user的BeanDefinition,然后注册到BeanDefitionRegistry中,如下图所示:
图片
注解@EnableConfigurationProperties源码中import了EnableConfigurationPropertiesRegistrar类,那么它是在什么阶段创建出BeanDefinition呢?
图片
最终配置了@EnableConfigurationProperties(User.class)中被获取,创建出name为my.user-com.alvinlkk.bean.User的BeanDefinition,如下图所示。
图片
而且@Component的顺序是优先于@EnableConfigurationProperties的。
现在BeanDefinitionBean定义信息已经有了,Spring就可以根据这些信息创建出Bean对象实例了,这一个过程是在finishBeanFactoryInitialization()方法中进行的,我们这里重点关注下@Autowird方法是如何进行装配的。
图片
根据类型匹配到Bean有多个的情况,会调用determineAutowireCandidate()方法进一步去根据name匹配bean。
所以对于配置注解ConfigurationProperties的类不要使用使用@Component注解让Spring管理,更推荐的做法是使用@EnableConfigurationProperties注解进行装载。
责任编辑:武晓燕 来源: JAVA旭阳 Spring容器Component(责任编辑:百科)
核心条款未达成共识 全通教育15亿元收购“吴晓波频道”会凉凉吗?
皇朝家居(01198.HK)发布公告:年度归母净利同比下降89.2%
前三季度交通固定资产投资完成22918亿元 运输结构持续优化
“双11”部分商品被抢购 大小超市参与热情不一 食品饮料是囤货首选
消息:年内A股再融资规模超万亿元 较去年同期增长24.31%