RabbitMQ學習系列:五、RabbitMQ整合Spring
最後學習一下RabbitMQ如何整合Spring,畢竟現在大多是使用框架來做專案。這篇主要使用的方式是XML配置。
介紹
RabbitMQ整合Spring的學習中,搭了兩個web專案,一個作為客戶端,一個作為服務端,放在一個專案中也可以實現效果,但畢竟RabbitMQ也是在這種類似的環境中使用的。客戶端會把info型別和error型別的日誌傳送給RabbitMQ,RabbitMQ根據所定義的路由與繫結的key分別把日誌訊息傳遞給不同的佇列。
客戶端專案結構:
客戶端實現
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向服務端傳送訊息 。