1. 程式人生 > >RabbitMQ學習系列:五、RabbitMQ整合Spring

RabbitMQ學習系列:五、RabbitMQ整合Spring

最後學習一下RabbitMQ如何整合Spring,畢竟現在大多是使用框架來做專案。這篇主要使用的方式是XML配置。

介紹

RabbitMQ整合Spring的學習中,搭了兩個web專案,一個作為客戶端,一個作為服務端,放在一個專案中也可以實現效果,但畢竟RabbitMQ也是在這種類似的環境中使用的。客戶端會把info型別和error型別的日誌傳送給RabbitMQ,RabbitMQ根據所定義的路由與繫結的key分別把日誌訊息傳遞給不同的佇列。
客戶端專案結構:
rabbitmq整合Spring專案結構

客戶端實現

RabbitMQ配置檔案

config.properties

# RabbitMQ config
rabbitmq.host=localhost
rabbitmq.username=guest
rabbitmq.password=guest
rabbitmq.port=5672

這裡在我本機的RabbitMQ,如果是在遠端主機上則要做相應修改。需要注意的是,我們訪問RabbitMQ管理介面是使用的15672埠,但通過連線訪問RabbitMQ是使用5672

XML配置


<?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:rabbit="http://www.springframework.org/schema/rabbit"
xmlns:context="http://www.springframework.org/schema/context" xmlns:mvc="http://www.springframework.org/schema/mvc" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.2.xsd http://www.springframework.org/schema/rabbit http://www.springframework.org/schema/rabbit/spring-rabbit-1.7.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.2.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.2.xsd"
>
<context:component-scan base-package="com.rabbitmq.spring"/> <context:property-placeholder location="classpath*:config.properties"/> <mvc:annotation-driven /> <mvc:default-servlet-handler/> <!--連線工廠--> <rabbit:connection-factory id="connectionFactory" host="${rabbitmq.host}" username="${rabbitmq.username}" password="${rabbitmq.password}" port="${rabbitmq.port}"></rabbit:connection-factory> <!--RabbitAdmin主要用於建立佇列和交換器以及繫結關係等。--> <rabbit:admin id="rabbitAdmin" connection-factory="connectionFactory"/> <!--宣告佇列--> <rabbit:queue name="rabbitmq_log_info" durable="true" auto-delete="false" /> <rabbit:queue name="rabbitmq_log_error" durable="true" auto-delete="false" /> <!--宣告路由並繫結佇列,指定routingKey--> <rabbit:direct-exchange name="hap.log.exchange" auto-delete="false" durable="true"> <rabbit:bindings> <rabbit:binding queue="rabbitmq_log_info" key="info"></rabbit:binding> <rabbit:binding queue="rabbitmq_log_error" key="error"></rabbit:binding> </rabbit:bindings> </rabbit:direct-exchange> <!--定義RabbitTemplate,用於傳送與接收訊息--> <rabbit:template id="rabbitTemplateLogInfo" connection-factory="connectionFactory" routing-key="info" exchange="hap.log.exchange" message-converter="jsonMessageConverter"></rabbit:template> <rabbit:template id="rabbitTemplateLogError" connection-factory="connectionFactory" routing-key="error" exchange="hap.log.exchange" message-converter="jsonMessageConverter"></rabbit:template> <!-- 訊息物件json轉換類 --> <bean id="jsonMessageConverter" class="org.springframework.amqp.support.converter.Jackson2JsonMessageConverter" /> </beans>

rabbit-admin 標籤如不宣告,則 rabbit:queue 與 rabbit:direct-exchange 標籤中必須新增 auto-declare 屬性為true ,表示如果佇列或路由不存在則自動宣告,如不宣告rabbit-admin,也不新增auto-declare屬性則啟動時會報宣告佇列錯誤,或佇列不存在。
rabbit:template 標籤中的routing-key、exchange也可以不在XML中配置,在類中傳送訊息時可以作為引數代入。則XML中只需要配置一個rabbit:template標籤即可

Service

Service介面

public interface ISendMessageService {
    public void sendInfoMessage(String message);

    public void sendErrorMessage(String message);
}

Service實現類

@Service
public class SendMessageService implements ISendMessageService{

    @Autowired
    @Qualifier("rabbitTemplateLogInfo")
    public RabbitTemplate rabbitTemplateLogInfo;

    @Autowired
    @Qualifier("rabbitTemplateLogError")
    private RabbitTemplate rabbitTemplateLogError;

    @Override
    public void sendInfoMessage(String message) {
        System.out.println("Info傳送訊息中>>>" + message);
        this.rabbitTemplateLogInfo.convertAndSend(message);
    }

    @Override
    public void sendErrorMessage(String message) {
        System.out.println("Error傳送訊息中>>>" + message);
        this.rabbitTemplateLogError.convertAndSend(message);
    }
}

RabbitTemplate的convertAndSend方法中,如果XML中已經配置好了對應的exchange與routingKey則可以直接傳入一個訊息進行傳送即可。如果沒有可以在引數中加入Exchange 與 routingkey

Controller

@Controller
@RequestMapping("/rabbitmqLog")
public class RabbitmqController {

    @Autowired
    @Qualifier("sendMessageService")
    ISendMessageService service = new SendMessageService();


    @RequestMapping(value = "/sendInfoLog",method = RequestMethod.GET)
    public void sendInfoMessage(String message){
        service.sendInfoMessage(message);
    }

    @RequestMapping("/sendErrorLog")
    public void sendErrorMessage(String message){
        service.sendErrorMessage(message);
    }

}

服務端實現

因為這裡只是做一個簡單的示例,所以服務端只做了監聽,沒有做什麼業務邏輯。

RabbitMQ配置檔案

這裡與客戶端是一樣的

XML配置

<?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:rabbit="http://www.springframework.org/schema/rabbit"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.2.xsd
                           http://www.springframework.org/schema/rabbit http://www.springframework.org/schema/rabbit/spring-rabbit-1.7.xsd
                           http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.2.xsd
                           http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd
                           http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.2.xsd">


    <context:component-scan base-package="com.rabbitmq.spring"/>
    <context:property-placeholder location="classpath*:config.properties"/>
    <mvc:annotation-driven />
    <mvc:default-servlet-handler/>
    <rabbit:connection-factory id="connectionFactory" host="${rabbitmq.host}" username="${rabbitmq.username}" password="${rabbitmq.password}" port="${rabbitmq.port}"></rabbit:connection-factory>
    <rabbit:admin id="rabbitAdmin" connection-factory="connectionFactory"/>
    <rabbit:queue name="rabbitmq_log_info" durable="true" auto-delete="false" />
    <rabbit:queue name="rabbitmq_log_error" durable="true" auto-delete="false" />

    <rabbit:listener-container connection-factory="connectionFactory" acknowledge="auto">
        <rabbit:listener ref="messageRecevicer" queues="rabbitmq_log_info"/>
        <rabbit:listener ref="messageRecevicer" queues="rabbitmq_log_error"/>
    </rabbit:listener-container>

    <bean id="messageRecevicer" class="com.rabbitmq.spring.listener.QueueListener"/>

    <!-- 訊息物件json轉換類 -->
    <bean id="jsonMessageConverter" class="org.springframework.amqp.support.converter.Jackson2JsonMessageConverter" />
</beans>

服務端的XML與客戶端不同的是多了監聽配置與監聽類的Bean,少了路由宣告與佇列繫結的配置。

監聽類

@Component
public class QueueListener implements MessageListener{
    @Override
    public void onMessage(Message message) {
        String msg = null;
        try {
            msg = new String(message.getBody(),"UTF-8");
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        System.out.println("監聽到 "+ message.getMessageProperties().getConsumerQueue()+" 佇列訊息:" + msg);
    }
}

測試

最後我們分別啟動客戶端與服務端。客戶端呼叫Controller向服務端傳送訊息 。
測試