最後學習一下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向服務端發送消息 。