【问题标题】:Spring Integration Load Balance to JMS QueuesSpring 集成负载平衡到 JMS 队列
【发布时间】:2018-08-24 18:02:45
【问题描述】:

我想从单个输入队列中获取 JMS 消息并将它们分散到 N 个输出队列中。

我有一个简单的流程,可以将消息转发到单个目的地,但不知道如何应用 LoadBalancer 以允许以循环方式处理多个目的地。

任何想法如何做到这一点?

@Configuration
public class TestLoadBalance {

    public static final String INPUT_QUEUE = "_dev.lb.input";
    public static final String OUTPUT_QUEUE_PREFIX = "_dev.lb.output-";


    @Bean
    public IntegrationFlow testLoadBalanceFlow(
            ConnectionFactory jmsConnectionFactory) {

        IntegrationFlow flow =  IntegrationFlows.from(
                Jms.messageDrivenChannelAdapter(jmsConnectionFactory)
                        .destination(INPUT_QUEUE)
        )
                .handle(buildOutput(jmsConnectionFactory, 1))
                // cant have 2nd handle. gets warn & flow end:
                // The 'currentComponent' (org.springframework.integration.jms.JmsSendingMessageHandler@516462cc) 
                // is a one-way 'MessageHandler' and it isn't appropriate to configure 'outputChannel'
                //.handle(buildOutput(jmsConnectionFactory, 2))
                .get();
        return flow;
    }


    private JmsSendingMessageHandler buildOutput(ConnectionFactory jmsConnectionFactory, int i){
        return Jms.outboundAdapter(jmsConnectionFactory)
                .destination(OUTPUT_QUEUE_PREFIX + i).get();
    }
}

【问题讨论】:

    标签: spring-integration spring-integration-dsl


    【解决方案1】:

    有几种方法可以做到这一点;您可以在频道上拥有多个订阅者...

    @Bean
    public IntegrationFlow inbound(ConnectionFactory cf) {
        return IntegrationFlows.from(Jms.messageDrivenChannelAdapter(cf)
                    .destination("foo"))
                .channel(roundRobin())
                .get();
    }
    
    @Bean
    public DirectChannel roundRobin() {
        return new DirectChannel();
    }
    
    @Bean
    public IntegrationFlow outbound1(ConnectionFactory cf) {
        return IntegrationFlows.from(roundRobin())
                .bridge() // otherwise log() will wire tap the roundRobin channel
                .log()
                .log(new LiteralExpression("Sending to bar"))
                .handle(Jms.outboundAdapter(cf)
                        .destination("bar"))
                .get();
    }
    
    @Bean
    public IntegrationFlow outbound2(ConnectionFactory cf) {
        return IntegrationFlows.from(roundRobin())
                .bridge() // otherwise log() will wire tap the roundRobin channel
                .log()
                .log(new LiteralExpression("Sending to baz"))
                .handle(Jms.outboundAdapter(cf)
                        .destination("baz"))
                .get();
    }
    

    或者,您可以使用目标表达式:

    @Bean
    public AtomicInteger toggle() {
        return new AtomicInteger();
    }
    
    @Bean
    public IntegrationFlow inbound(ConnectionFactory cf) {
        return IntegrationFlows.from(Jms.messageDrivenChannelAdapter(cf)
                        .destination("foo"))
                .handle(Jms.outboundAdapter(cf)
                        .destinationExpression("@toggle.getAndIncrement() % 2 == 0 ? 'bar' : 'baz'"))
                .get();
    }
    
    @JmsListener(destination = "bar")
    public void bar(String in) {
        System.out.println("received " + in + " from bar");
    }
    
    @JmsListener(destination = "baz")
    public void baz(String in) {
        System.out.println("received " + in + " from baz");
    }
    

    结果:

    received test1 from bar
    received test2 from baz
    

    【讨论】:

      【解决方案2】:

      根据 Gary 的示例,我使用了 destinationExpression 方法:

      @Configuration
      public class TestLoadBalance {
      
          public static final String INPUT_QUEUE = "_dev.lb.input";
          public static final String OUTPUT_QUEUE_PREFIX = "_dev.lb.output-";
      
          @Bean
          public JmsDestinationPartitioner partitioner() {
              return new JmsDestinationPartitioner(OUTPUT_QUEUE_PREFIX,1,3);
          }
      
          @Bean
          public IntegrationFlow testLoadBalanceFlow(
                  ConnectionFactory jmsConnectionFactory) {
      
              IntegrationFlow flow =  IntegrationFlows.from(
                      Jms.messageDrivenChannelAdapter(jmsConnectionFactory)
                              .destination(INPUT_QUEUE)
              )
                      .handle(Jms.outboundAdapter((jmsConnectionFactory))
                              .destinationExpression("@partitioner.nextDestination()"))
                      .get();
              return flow;
          }
      
      }
      

      使用 AtomicInt 的包装器来处理带有前缀的命名:

      public class JmsDestinationPartitioner {
      
          private int min;
          private int max;
          private String prefix;
      
          private AtomicInteger current;
      
          public JmsDestinationPartitioner(String prefix, int min, int max){
              this.prefix = prefix;
              this.min = min;
              this.max = max;
              current = new AtomicInteger(min);
          }
      
      
          public int getAndIncrement(){
              int  i = current.get();
              current.getAndIncrement();
              if (current.get() > max){
                  current.set(min);
              }
              return i;
          }
      
          public String nextDestination(){
              return prefix + getAndIncrement();
          }
      }
      

      【讨论】:

        猜你喜欢
        • 2018-11-23
        • 2019-04-30
        • 2013-03-23
        • 1970-01-01
        • 2019-05-22
        • 2016-03-29
        • 2018-07-17
        • 2017-06-19
        • 1970-01-01
        相关资源
        最近更新 更多