现在在配置类里面创建一个bean date
1 |
|
时间并不是一成不变的,我想要获取当前时间呢,应该怎么覆盖已经在容器内bean。我一开始想到使用org..cloud.context.scope.refresh.RefreshScope
,但是Spring boot项目并没有使用到Spring Cloud包,这个走不通,就试着registerBean
动态注册相同名字bean,想着能不能覆盖容器内bean,毕竟所谓容器只不过是Map而已,只要通过机制覆盖掉Map 上value 就可以实现动态刷新了。
1 | private ApplicationContext applicationContext; |
执行这个请求,直接报错了,抛出了一个BeanDefinitionOverrideException异常,bean不能被覆盖。在DefaultListableBeanFactory.registerBeanDefinition
可以看到其中原因
1 | public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) |
然后发现这个allowBeanDefinitionOverriding 在SpringBoot 刚初始化时,在SpringApplication 会初始化这个值,在SpringApplication.prepareContext
1 | private void prepareContext(DefaultBootstrapContext bootstrapContext, ConfigurableApplicationContext context, |
接着看下配置文件值如何设置到SpringApplication.allowBeanDefinitionOverriding
1 | private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners, |
在application.properties 添加下面配置
spring.main.allow-bean-definition-overriding=true
重启后重新执行HTTP 请求,没有报错了,重新获取date 这个bean,时间也变成最新值了。
心得
添加多这一个配置估计为了兼容不同组件间可能存在一些bean 冲突情况,后面初始化bean组件可以覆盖Spring 内部已经创建组件。假如现在Spring 内部已经初始化bean A,并且成功加入到容器中了,这时加载再加载Spring 组件也有一个Class 继承bean A,这是需要添加到容器中。如果没有beanName 相同覆盖的机制,组件在初始化就会失败。
还有一点值得注意的,registerBean 这个方法只有在容器中删除这个bean 缓存,如何已经将bean注入到对象属性中,这时这个值不会变化的,需要手动调用beanFactory.getBean(“beanName”),因为只有这个bean不存在时候才会执行初始化。如果有这种bean刷新场景可以使用@Lookup来生成一个代理方法。
1 |
|