【问题标题】:How to add bean instance at runtime in spring WebApplicationContext?如何在 Spring WebApplicationContext 中在运行时添加 bean 实例?
【发布时间】:2017-08-20 10:55:17
【问题描述】:

所以,标题很简单。我有一个处理程序类DynamicBeanHandler,它实现了spring 提供的BeanDefinitionRegistryPostProcessor 接口。在这个类中,我添加了多个 SCOPE_SINGLETON bean,它们的 bean 类设置为 MyDynamicBean,如下所示-

GenericBeanDefinition myBeanDefinition = new GenericBeanDefinition();
myBeanDefinition.setBeanClass(MyDynamicBean.class);
myBeanDefinition.setScope(SCOPE_SINGLETON);
myBeanDefinition.setPropertyValues(getMutableProperties(dynamicPropertyPrefix));
registry.registerBeanDefinition(dynamicBeanId, myBeanDefinition);

方法getMutableProperties()返回一个MutablePropertyValues的对象。

稍后,我使用SpringUtil.getBean(dynamicBeanId) 获取所需的MyDynamicBean 实例,其中SpringUtil 类实现ApplicationContextAware。这一切都很好。当我想删除其中一个实例并稍后在我没有注册表实例的地方添加一个新实例时,问题就出现了。谁能帮我想办法做到这一点?

下面是SpringUtil类的代码-

public class SpringUtil implements ApplicationContextAware {

    private static ApplicationContext applicationContext;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        SpringUtil.applicationContext = applicationContext;
    }

    public static ApplicationContext getApplicationContext() {
        return applicationContext;
    }

    public static Object getBean(String beanId) {
        return applicationContext.getBean(beanId);
    }

    public static <T> T getBean(String beanId, Class<T> beanClass) {
        return applicationContext.getBean(beanId, beanClass);
    }
}

【问题讨论】:

  • 您为什么要这样做?您是否要延迟初始化?
  • 所以,我想这样做,因为MyDynamicBean 包含一些我想在运行时以编程方式从数据库更新的属性。请注意,我想在上下文初始化后更新 bean 实例并添加一个新的 bean 实例。
  • @Abhishek 你能发布你当前SpringUtil的代码吗?
  • @javaguy - 更新了代码。请检查。

标签: java spring spring-mvc


【解决方案1】:

您可以通过以下方式以编程方式创建具有注入依赖项的 bean:

AutowireCapableBeanFactory#createBean

完全创建给定类的新 bean 实例 自动接线策略。此接口中定义的所有常量都是 这里支持。执行 bean 的完全初始化,包括 所有适用的 BeanPostProcessors。

@Autowired
ApplicationContext context;

AutowireCapableBeanFactory factory = context.getAutowireCapableBeanFactory();
MyDynamicBean bean = (MyDynamicBean) factory.createBean(MyDynamicBean.class, AUTOWIRE_CONSTRUCTOR, false);

【讨论】:

  • 豆子的名字怎么样?
【解决方案2】:

您可以这样做,而不是自动装配 WebApplicationContext

@Autowired
private GenericWebApplicationContext context;

然后你可以注册新bean或删除旧bean并注册新bean

AutowireCapableBeanFactory factory = context.getAutowireCapableBeanFactory();
BeanDefinitionRegistry registry = (BeanDefinitionRegistry) factory;
registry.removeBeanDefinition("myBean");
context.registerBean("myBean", MyBean.class, () -> new MyBean());

【讨论】:

    【解决方案3】:

    您可以使用BeanDefinitionRegistry(查看here 的API)来动态删除或注册bean。

    因此,在您的 SpringUtil 类中,您可以添加以下方法以使用 removeBeanDefinition() 删除现有的 bean 定义,然后使用 registerBeanDefinition() 添加新的 bean 定义。

    public void removeExistingAndAddNewBean(String beanId) {
    
       AutowireCapableBeanFactory factory = 
                       applicationContext.getAutowireCapableBeanFactory();
       BeanDefinitionRegistry registry = (BeanDefinitionRegistry) factory;
       registry.removeBeanDefinition(beanId);
    
        //create newBeanObj through GenericBeanDefinition
    
        registry.registerBeanDefinition(beanId, newBeanObj);
    }
    

    【讨论】:

    • 所以,如果这种类型转换有效,我可以在任何我可以接触到ApplicationContext 的课程中​​做到这一点。是这样吗?
    • 但是ApplicationContext只保留在SpringUtil中,因为在太多地方暴露ApplicationContext不是一个好主意
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-09-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多