简体   繁体   English

使用与RabbitMQ的Spring集成

[英]Using Spring Integration with RabbitMQ

I'm in the process of developing a messaging interface for one of our applications. 我正在为我们的某个应用程序开发消息传递接口。 The application is a service which is designed to accept a "Job", do some processing, and return the result (in the form of a File actually). 该应用程序是一种服务,旨在接受“作业”,进行一些处理,并返回结果(实际上以文件的形式)。

The idea is to use RabbitMQ as the messaging infrastructure and Spring AMQP to handle protocol specific details. 我们的想法是使用RabbitMQ作为消息传递基础架构,使用Spring AMQP来处理协议特定的细节。

I do not want to have a tight coupling from my code to Spring AMQP, so I would like to use Spring Integration to hide the messaging api. 我不希望从我的代码到Spring AMQP紧密耦合,所以我想使用Spring Integration来隐藏消息api。 So basically I want this: 基本上我想要这个:

Message sent to RabbitMQ ====> Spring AMQP ====> Spring Integration ====> MyService ====> reply all the way back to RabbitMQ 消息发送到RabbitMQ ====> Spring AMQP ====> Spring Integration ====> MyService ====>回复一直回到RabbitMQ

I'm trying to work out the XML configuration required to wire this together, but I'm having problems with the multiple levels of abstraction and different terminology. 我正在尝试计算将这些连接在一起所需的XML配置,但我遇到了多层抽象和不同术语的问题。 Finding a working example that demonstrates Spring Integration on top of Spring AMQP/RabbitMQ has proven to be surprisingly difficult, despite the fact that this sort of setup feels very "best practice" to me. 找到一个在Spring AMQP / RabbitMQ之上演示Spring Integration的工作示例已经证明是非常困难的,尽管这种设置对我来说是非常“最佳实践”。

1) So.. Could some brilliant soul out there take a quick look at this and perhaps push me in the right direction? 1)那么......有些聪明的灵魂可以快速看一下这个并且可能会让我朝着正确的方向前进吗? What do I need and what don't I need? 我需要什么,不需要什么? :-) :-)

2) Ideally the queue should be multithreaded, meaning that a taskExecutor should hand off multiple messages to my jobService for parallel processing. 2)理想情况下,队列应该是多线程的,这意味着taskExecutor应该将多条消息传递给我的jobService以进行并行处理。 What configuration would be required? 需要什么配置?

 <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:util="http://www.springframework.org/schema/util"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:rabbit="http://www.springframework.org/schema/rabbit"
    xmlns:int="http://www.springframework.org/schema/integration"
    xmlns:int-amqp="http://www.springframework.org/schema/integration/amqp"
    xmlns:int-stream="http://www.springframework.org/schema/integration/stream"
    xsi:schemaLocation="
    http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
    http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
    http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.0.xsd
    http://www.springframework.org/schema/rabbit http://www.springframework.org/schema/rabbit/spring-rabbit.xsd
    http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration.xsd
    http://www.springframework.org/schema/integration/amqp http://www.springframework.org/schema/integration/amqp/spring-integration-amqp.xsd
    http://www.springframework.org/schema/integration/stream http://www.springframework.org/schema/integration/stream/spring-integration-stream.xsd
    ">

    <context:component-scan base-package="com.myprogram.etc" />

    <!-- Messaging infrastructure: RabbitMQ -->

    <bean id="connectionFactory" class="org.springframework.amqp.rabbit.connection.CachingConnectionFactory">
        <constructor-arg value="${ei.messaging.amqp.servername}" />
        <property name="username" value="${ei.messaging.amqp.username}" />
        <property name="password" value="${ei.messaging.amqp.password}" />
    </bean>

    <rabbit:connection-factory id="connectionFactory" />

    <rabbit:admin connection-factory="connectionFactory"/>

    <!-- From RabbitMQ -->

    <int-amqp:inbound-gateway request-channel="fromAMQP" reply-channel="toAMQP" queue-names="our-product-name-queue" connection-factory="connectionFactory"/>

    <!-- Spring Integration configuration -->

    <int:channel id="fromAMQP">
        <!-- Is this necessary?? -->
        <int:queue/>
    </int:channel>

    <!-- JobService is a @Service with a @ServiceActivator annotation -->
    <int:service-activator input-channel="fromAMQP" ref="jobService"/>
</beans>

I'm as much a noob to spring-integration and spring-integration-amqp as you, I suspect, but I did get something working based in part on the one sample project. 我怀疑,对于弹簧集成和弹簧集成amqp来说,我也是一个菜鸟,但我确实得到了一些基于一个示例项目的工作。

For rabbitmq infrastructure, I have the following: 对于rabbitmq基础设施,我有以下内容:

<rabbit:connection-factory id="rabbitConnectionFactory"/>

<rabbit:template id="amqpTemplate" connection-factory="rabbitConnectionFactory"/>

<rabbit:admin connection-factory="rabbitConnectionFactory"/>

<!-- some attributes seemed to be ok with queue name, others required id
  -- so I used both with the same value -->
<rabbit:queue id='test.queue' name='test.queue'/>

<rabbit:direct-exchange name:"my.exchange">
    <rabbit:bindings>
        <rabbit:binding queue="test.queue" key="test.binding"/>
    </rabbit:bindings>
</rabbit:direct-exchange>

To send a message to rabbitmq, I have the following: 要向rabbitmq发送消息,我有以下内容:

<!-- This is just an interface definition, no implementation required
  -- spring will generate an implementation which puts a message on the channel -->
<int:gateway id="backgroundService", 
         service-interface="com.company.BackgroundService"
             default-request-channel="toRabbit"

<int:channel id:"toRabbit"/>

<!-- used amqpTemplate to send messages on toRabbit channel to rabbitmq -->
<int-amqp:outbound-channel-adapter channel:"toRabbit" 
                               amqp-template="amqpTemplate" 
                   exchange-name="my.exchange" 
                   routing-key="test.binding"/>

And to receive messages I have the following: 要接收消息,我有以下内容:

<int:service-activator input-channel="fromRabbit" 
                       ref="testService" 
                       method="serviceMethod"/>


// from rabbitmq to local channel
<int-amqp:inbound-channel-adapter channel="fromRabbit" 
                                  queue-names="test.queue" 
                                  connection-factory="rabbitConnectionFactory"/>

<int:channel id="fromRabbit"/>

Some caveats - the documentation of amqp integration in spring-integration says it is possible to to a synchronous send and receive of a return value, but I haven't figured that out yet. 一些警告 - spring-integration中的amqp集成文档说可以同步发送和接收返回值,但我还没想到。 When my service-activator method returned a value, it caused an exception to get thrown, putting the message back on rabbitmq (and generating an infinite loop, since it would then receive the message again and throw the exception again). 当我的service-activator方法返回一个值时,它会引发异常抛出,将消息放回rabbitmq(并生成一个无限循环,因为它会再次接收消息并再次抛出异常)。

My BackgroundService interfacde looks like this: 我的BackgroundService interfacde看起来像这样:

package com.company

import org.springframework.integration.annotation.Gateway

public interface BackgroundService {

    //@Gateway(requestChannel="someOtherMessageChannel")
    public String sayHello(String toWho)

}

You can specify a channel on every method via the annotation if you don't wish to use the default channel configured in the spring bean. 如果您不希望使用spring bean中配置的默认通道,则可以通过注释在每个方法上指定通道。

The service attached to the service-activator looks like this: 附加到服务激活器的服务如下所示:

package com.company;

class TestService {

    public void serviceMethod(String param) {
    log.info("serviceMethod received: " + param");
    //return "hello, " + param;
    }
}

When I had everything wired up locally without rabbitmq involved, the return value was correctly received by the caller. 当我在没有涉及rabbitmq的情况下将所有内容连接到本地时,调用者正确接收了返回值。 When I went to rabbitmq channels, I got the aforementioned infinite loop when an exception was thrown after returning a value. 当我访问rabbitmq频道时,在返回值后抛出异常时,我得到了前面提到的无限循环。 It is surely possible or else it wouldn't be possible to wire in different channels without modifying code, but I'm not sure what the trick is yet. 它肯定是可能的,否则就不可能在不修改代码的情况下在不同的通道中连接,但我不确定这个技巧是什么。 Please respond with a solution if you figure it out. 如果你想出来,请回答一个解决方案。 Obviously, you can put whatever routing, transforming, and filtering you like between the endpoints, as needed. 显然,您可以根据需要在端点之间放置您喜欢的路由,转换和过滤。

Don't be surprised if my XML excerpts above have typos in them. 如果上面的XML摘录中存在拼写错误,请不要感到惊讶。 I had to convert back to xml from groovy DSL, so I could have made mistakes. 我不得不从groovy DSL转换回xml,所以我本可以犯错误。 But the intent should be clear enough. 但意图应该足够明确。

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

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