如何使用 Spring Boot 监听动态目的地? [英] How to listen to dynamic destinations using Spring Boot?

查看:42
本文介绍了如何使用 Spring Boot 监听动态目的地?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我们有一个使用 Spring Boot 及其 JMS 工具的应用程序.在运行时,我们有不同的生产者在线跳转并告诉我们的应用程序要收听的主题或队列的名称.现在,我们有:

We have an application using Spring Boot and its JMS facility. At runtime, we have different producers that jump online and tell our application the name of the topic or queue to listen to. Right now, we have:

@JmsListener(destination = "helloworld.q")
public void receive(String message) {
  LOGGER.info("received message='{}'", message);
}

当我们向 helloworld.q 主题发送消息时有效.问题是,直到运行时我们才会知道主题的名称是什么,而且 JmsListener 似乎想要一个常量表达式.

which works when we send a message to the helloworld.q topic. The problem is, we won't know what the name of the topic will be until runtime, and JmsListener seems to want a constant expression.

消息生产者将挂接到我们的 ActiveMQ 实例并广播一条消息告诉我们我们需要开始收听他们的主题,例如Wasabi"、WhitePaper"、SatelliteMajor"、BigBoosters"等.没有办法在运行时知道我们需要开始收听哪些主题.

Message producers will hook into our ActiveMQ instance and broadcast a message telling us we need to start listening to their topic, such as "Wasabi", "WhitePaper", "SatelliteMajor", "BigBoosters", etc. There is no way to know at runtime which topics we'll need to start listening to.

我已经阅读了解释如何在运行时监听主题/队列的 Spring 文档(有点):

I've read the Spring documentation that explains how to listen to topics/queues at runtime (sort of):

@Configuration
@EnableJms
public class ReceiverConfig implements JmsListenerConfigurer {

  @Override
  public void configureJmsListeners(JmsListenerEndpointRegistrar registrar) {
    SimpleJmsListenerEndpoint endpoint = new SimpleJmsListenerEndpoint();
    endpoint.setId("myJmsEndpoint");
    endpoint.setDestination("anotherQueue");
    endpoint.setMessageListener(message -> {
        // processing
    });
    registrar.registerEndpoint(endpoint);
  }

  // other methods...
}

作为测试,我已将其放入我们的 Receiver 配置中,当我们发送消息时它确实会被调用.问题是,Spring 使所有这些东西都被自动调用,我们不知道在哪里以及如何为该方法指定端点需要侦听的主题/队列的名称.此外,消息侦听器似乎永远不会被调用,但这是一个单独的问题;如果我们至少可以发送自定义主题或队列供其收听,我相信我们可以解决它.

I've shoved that into our Receiver config as a test, and it does get called when we send a message. The problem is, Spring makes all this stuff get called automagically and we don't know where and how to give this method the name of the topic/queue the endpoint needs to listen to. Also, the message listener never seems to get called, but that's a separate problem; I'm sure we can solve it if we at least can send the custom topic or queue for it to listen to.

我们使用的是 Spring 2.x.

We're using Spring 2.x.

推荐答案

您可以使用属性占位符作为目标名称

You can use a property placeholder for the destination name

@SpringBootApplication
public class So56226984Application {

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

    @JmsListener(destination = "${foo.bar}")
    public void listen(String in) {
        System.out.println(in);
    }

    @Bean
    public ApplicationRunner runner(JmsTemplate template) {
        return args -> template.convertAndSend("baz", "qux");
    }

}

然后设置属性,例如在 application.yml 中用于 Spring Boot 应用程序,或启动 JVM 时的命令行属性

Then set the property, e.g. in application.yml for a Spring Boot app, or a command-line property when launching the JVM

-Dfoo.bar=baz

编辑

您可以使侦听器 bean 成为原型并调整环境属性.

You can make the listener bean a prototype and adjust an environment property.

@SpringBootApplication
public class So56226984Application {

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

    @Bean
    public ApplicationRunner runner(JmsTemplate template, JmsListenerEndpointRegistry registry,
            ConfigurableApplicationContext context) {

        return args -> {
            Scanner scanner = new Scanner(System.in);
            String queue = scanner.nextLine();
            Properties props = new Properties();
            context.getEnvironment().getPropertySources().addLast(new PropertiesPropertySource("queues", props));
            while (!"quit".equals(queue)) {
                System.out.println("Adding " + queue);
                props.put("queue.name", queue);
                context.getBean("listener", Listener.class);
                template.convertAndSend(queue, "qux sent to " +  queue);
                System.out.println("There are now " + registry.getListenerContainers().size() + " containers");
                queue = scanner.nextLine();
            }
            scanner.close();
        };
    }

    @Bean
    @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
    public Listener listener() {
        return new Listener();
    }

    public static class Listener {

        @JmsListener(destination = "${queue.name}")
        public void listen(String in) {
            System.out.println(in);
        }

    }
}

这篇关于如何使用 Spring Boot 监听动态目的地?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆