繁体   English   中英

如何以编程方式刷新 spring bean

[英]How to programmatically refresh spring bean

我们有一个 Spring 应用程序负责执行一些预计将 24 x 7 全天候运行的集成工作。

我们使用的集成模式之一是使用一组集群 IBM MQ 队列管理器的 JMS 消息传递。 对于集群 IBM MQ 队列管理器,如果其中一个队列管理器出现故障,您需要重新实例化 Queue Connection Factory bean,以便连接能够与其余仍在运行的队列管理器一起工作。

我们实施了 JMS 健康检查,并且 IBM MQ 队列管理器的状态发生了变化,我们以编程方式重新启动 spring 上下文,结果重新创建了队列连接工厂 bean,一切正常。

然而,这对我们来说并不理想,因为我们的应用程序的其他部分与 IBM MQ 无关,工作正常,实际上可以在处理东西的过程中。 因此,我们更愿意只重新创建 JMS 上下文,几乎是重新创建队列连接工厂 bean 和一些其他依赖于它们的 bean(消息侦听器容器、JmsTemplats 等),而不是重新启动整个应用程序上下文。

我发现这篇文章how-to-reinitialize-a-spring-bean并尝试实施解决方案2)Delete & Register bean in registry但我无法让它工作。

// If I call below:
beanFactory.destroySingleton(qcfName);
var qcf = jmsConfig.connectionFactory();
beanFactory.registerSingleton(qcfName, qcf);

// I get this exception:
Could not register object [org.springframework.cloud.sleuth.instrument.messaging.LazyConnectionFactory@5a0fb814] under bean name 'connectionFactory':
there is already object [org.springframework.cloud.sleuth.instrument.messaging.LazyConnectionFactory@5a0fb814] bound


// If I call below:
beanFactory.destroySingleton(qcfName);
beanFactory.removeBeanDefinition(qcfName);
var qcf = jmsConfig.connectionFactory();
beanFactory.registerSingleton(qcfName, qcf);

// I am getting this exception:
No bean named 'connectionFactory' available

我尝试了一些其他排列,例如destroyBean ,但我无法让它工作。

知道我做错了什么以及我应该如何解决它? 提前感谢您的投入。

我明白你想做什么,所以我测试了几种方法并得到了这个:

@SpringBootApplication
public class DemoApplication implements CommandLineRunner {

    @Autowired
    AnnotationConfigReactiveWebServerApplicationContext context;

    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }

    @Override
    public void run(String... args) throws Exception {
        context.registerBean("jms", Bean1.class, () -> new Bean1());
        var jmsBean1 = context.getBean(Bean1.class);
        jmsBean1.hello();
        var jmsBean2 = context.getBean(Bean1.class);

        context.removeBeanDefinition("jms");

        context.registerBean("jms", Bean1.class, () -> new Bean1());
        var jmsBean3 = context.getBean(Bean1.class);

        System.out.println(jmsBean1.hashCode());
        System.out.println(jmsBean2.hashCode());
        System.out.println(jmsBean1 == jmsBean2);
        System.out.println(jmsBean3.hashCode());
        System.out.println(jmsBean1 == jmsBean3);

    }

}

class Bean1 {
    public void hello() {
        System.out.println("hello");
    }
}

结果是:

hello
405390165 // jmsBean1 hashcode -> singleton
405390165 //jmsBean2 hashcode -> singleton
true // jmsBean1 == jmsBean2
1182556970 // jmsBean3 hashcode
false // jmsBean3 is different object

如您所见,注册新 bean 时默认的 bean scope 是 singleton。
注意:删除 bean 定义后尽量不要保留对旧 object 的引用,因为 JVM GC

测试于:Spring 引导 (v2.6.3)
spring框架(5.3.15)

我的测试项目是 Reactive Web 项目,因为您看到注入了 ReacttiveApplicationContext,这取决于您必须注入上下文类型的项目。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM