前一篇博客我们提到, 如果bean是prototype或者刷新重新create后, 读取还是旧的properties, 所以从根本来说, 我们需要更新BeanDefinition,如此才能保证在重新初始化Bean的时候使用最新的配置。
运行时动态注册 bean 到 spring 容器
使用主要通过BeanDefinitionBuilder
构建BeanDefinition, 然后通过DefaultListableBeanFactory.registerBeanDefinition
注册到容器中:
BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(SomeClass.class); |
registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
的内部逻辑如下, 主要是验证BeanDefinition和清除缓存:
|
更新依赖这个动态 Bean 的 Bean
注册之后, 如果使用singleton模式的话, 由于singleton实例和缓存并没有改变, 所以要进行更新DynamicBean.
方法1: destroySingleton
这个方法简单粗暴, 使用 destroyXXX
可以销毁旧的Bean :
factory.destroySingleton("calculation"); |
例如 org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#destroySingleton
:
public void destroySingleton(String beanName) { |
如上, 内部的singletonObjects singletonFactories earlySingletonObjects registeredSingletons containedBeans containedBeanMap
等记录会清除掉这个Bean.
当下次需要这个Bean的时候, 如下面 org.springframework.beans.factory.support.AbstractBeanFactory#doGetBean
代码所示, 如果没有缓存, 就会重新创建这个Bean.
protected <T> T doGetBean( |
从上可知, 因为已经destroy了DynamicBean, 所以Object sharedInstance = getSingleton(beanName)
是null的, 所以需要重新缓存DynamicBean, org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#doCreateBean
被调用, 这样我们的修改就被刷新了.
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args) { |
方法2: WrapBean
- 一个比较好的策略是定义一个 WrapBean 包一下这个可能在runtime被动态更新的 DynamicBean, 大概如下:
public class WrapBean { |
这样的话, 动态修改后只需要更新这个WrapBean的dynamicBean, 而且对系统的影响相对较小.
参考
http://stackoverflow.com/questions/15328904/dynamically-declare-beans-at-runtime-in-spring
http://stackoverflow.com/questions/12800769/replace-spring-bean-in-one-context-with-mock-version-from-another-context
http://stackoverflow.com/questions/11606504/registering-beansprototype-at-runtime-in-spring
http://stackoverflow.com/questions/8711560/dynamic-creation-of-beans-in-spring
http://shayanth.blogspot.com/2009/10/dynamic-bean-creation-in-spring.html
http://stackoverflow.com/questions/4540713/add-bean-programatically-to-spring-web-app-context
http://stackoverflow.com/questions/27998502/java-spring-recreate-specific-bean