简体   繁体   English

如何以编程方式刷新 spring bean

[英]How to programmatically refresh spring bean

We have a Spring application responsible for doing some integration work that is expected to be up and running 24 x 7.我们有一个 Spring 应用程序负责执行一些预计将 24 x 7 全天候运行的集成工作。

One of the integration patterns we use is JMS messaging using a bunch of clustered IBM MQ queue managers.我们使用的集成模式之一是使用一组集群 IBM MQ 队列管理器的 JMS 消息传递。 With clustered IBM MQ queue managers if one of the queue manager goes down you need to reinstantiate the Queue Connection Factory beans in order for the connectivity to work with the remaining queue managers that are still up.对于集群 IBM MQ 队列管理器,如果其中一个队列管理器出现故障,您需要重新实例化 Queue Connection Factory bean,以便连接能够与其余仍在运行的队列管理器一起工作。

We put in place JMS health checks and the status of the IBM MQ queue managers changes we programatically restart the spring context and as a result the Queue Connection Factory beans get recreated and everything works just fine.我们实施了 JMS 健康检查,并且 IBM MQ 队列管理器的状态发生了变化,我们以编程方式重新启动 spring 上下文,结果重新创建了队列连接工厂 bean,一切正常。

However this is not ideal for us because other parts of our application not related to IBM MQ works just fine and actually can be in the middle of processing stuff.然而,这对我们来说并不理想,因为我们的应用程序的其他部分与 IBM MQ 无关,工作正常,实际上可以在处理东西的过程中。 Because of this we would prefer to only recreate the JMS context, pretty much recreating the Queue Connection Factory beans and a few other beans that depend on those (message listener containers, JmsTemplats, etc) rather than restarting the whole application context.因此,我们更愿意只重新创建 JMS 上下文,几乎是重新创建队列连接工厂 bean 和一些其他依赖于它们的 bean(消息侦听器容器、JmsTemplats 等),而不是重新启动整个应用程序上下文。

I found this post how-to-reinitialize-a-spring-bean and tried to implement solution 2)Delete & Register bean in registry but I could not get it to work.我发现这篇文章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

I tried some other permutations such as destroyBean but I could not get it to work.我尝试了一些其他排列,例如destroyBean ,但我无法让它工作。

Any idea what I am doing wrong and how should I fix it?知道我做错了什么以及我应该如何解决它? Thank you in advance for your inputs.提前感谢您的投入。

I understand what you wan to do, so I tested a few ways and got this:我明白你想做什么,所以我测试了几种方法并得到了这个:

@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");
    }
}

the result is:结果是:

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

As you can see the default bean scope is singleton when you register new bean.如您所见,注册新 bean 时默认的 bean scope 是 singleton。
Note : after remove bean definition try not to keep reference to old object because of JVM GC注意:删除 bean 定义后尽量不要保留对旧 object 的引用,因为 JVM GC

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

My test project was Reactive Web project because of that you saw ReacttiveApplicationContext injected, depends on your project you have to inject your context type.我的测试项目是 Reactive Web 项目,因为您看到注入了 ReacttiveApplicationContext,这取决于您必须注入上下文类型的项目。

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

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