之前寫過按照官方文檔學習使用RabbitMQ,瞭解了大概之後,我們可以開始嘗試在項目裏使用它。
1.前提準備
RabbitMQ,可以搭建在linux環境和windows環境。安裝比較簡單,這邊先不贅述了。以後補上。
我們要引入jar包,給出maven
<dependency>
<groupId>org.springframework.amqp</groupId>
<artifactId>spring-rabbit</artifactId>
<version>2.0.3.RELEASE</version>
</dependency>
版本自行選擇。
開一個項目,這裏是使用xml去配置。
applicationContext.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:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd">
<description>Spring公共配置</description>
<!-- 掃描註解 -->
<context:component-scan base-package="com.george"/>
<context:annotation-config/>
<!-- mq服務 生產者配置 -->
<import resource="classpath:context/applicationContext-producer-mq.xml"/>
<!-- mq服務 消費者配置 -->
<import resource="classpath:context/applicationContext-consumer-mq.xml"/>
</beans>
準備一下properties文件,消費者和生產者都需要!
mq.properties
#參數
mq.host = 主機ip
mq.username = 用戶名
mq.password = 密碼
mq.port = 5672
mq.vhost = /
#消息確認
mq.publisher-confirms = true
#緩存數量,默認25
mq.channel-cache-size = 50
1.生產者
我們現在先安排生產者:
在業務代碼中,我們一般都期望這種調用能夠儘可能的簡便。所以最好的情況就是通過注入和設置參數我們可以直接發送消息。
applicationContext-producer-mq.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"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/rabbit http://www.springframework.org/schema/rabbit/spring-rabbit.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<!-- 消息對象json轉換類 -->
<bean id="jsonMessageConverter" class="org.springframework.amqp.support.converter.Jackson2JsonMessageConverter" />
<!-- 配置文件位置 -->
<context:property-placeholder ignore-unresolvable="true" location="classpath*:mq.properties" ignore-resource-not-found="true"/>
<!-- 連接工廠配置 -->
<rabbit:connection-factory id="connectionFactory"
host="${mq.host}"
port="${mq.port}"
username="${mq.username}"
password="${mq.password}"
virtual-host="${mq.vhost}"
publisher-confirms="${mq.publisher-confirms}"
channel-cache-size="${mq.channel-cache-size}"/>
<rabbit:admin connection-factory="connectionFactory"/>
<!--定義消息隊列-->
<!-- durable:持久化,是否持久化日誌,恢復消息隊列 -->
<!-- auto-delete:當所有消費者客戶端斷開連接後,是否自動刪除隊列 -->
<!-- exclusive:是否是創建者的私有隊列,斷開後自動刪除 -->
<!-- auto-declare:是否自動聲明 -->
<rabbit:queue name="queue1" durable="true" auto-delete="false" exclusive="false" auto-declare="true"/>
<rabbit:queue name="queue2"/>
<!-- 定義交換機 -->
<rabbit:direct-exchange id="directExchange" name="directExchange" durable="true" auto-delete="false">
<!-- 綁定隊列 -->
<rabbit:bindings>
<rabbit:binding queue="queue1" key="queue1"/>
<!--<rabbit:binding queue="queue2" key="queue2"/>-->
</rabbit:bindings>
</rabbit:direct-exchange>
<!-- rabbit模板聲明 -->
<rabbit:template id="rabbitTemplateDirect"
connection-factory="connectionFactory"
exchange="directExchange"
routing-key="queue1"/>
<!--<rabbit:template id="rabbitTemplateTopic"-->
<!--connection-factory="connectionFactory"-->
<!--exchange="topicExchange"-->
<!--routing-key="queue2" />-->
<!-- 監聽處理 -->
<bean id="queueListener" class="com.george.QueueListener"/>
<!-- 監聽器 -->
<rabbit:listener-container connection-factory="connectionFactory" acknowledge="auto">
<rabbit:listener ref="queueListener" method="execute" queue-names="queue1"/>
</rabbit:listener-container>
</beans>
這裏單獨解釋一下template,這個就是在代碼裏要自動注入的了,所以我們需要現在這裏給他配置好,可以設置其id,交換機和rouing-key。這邊選用常見又容易講的direct模式。當然其他的可以配置, 只要id不重複就可以。其他的寫了註釋就不多說啦。
現在我去創建了service和它的實現類
@Service("messageProducer")
public class MessageProducerImpl implements MessageProducer {
@Resource(name = "rabbitTemplateDirect")
private AmqpTemplate rabbitTemplateDirect;
@Override
public void sendDataToQueue(String exchangeName, String routingKey, Object object) throws Exception {
rabbitTemplateDirect.convertAndSend(routingKey, object);
}
}
在注入的時候,@Resource的name屬性就對應着xml中配置的template的id,這樣我們就可以選擇我們想要的。
請注意!!!
最好強行拋出異常,等使用的時候進行try/catch,避免因爲rabbitmq無法啓動或者其他問題,導致業務流程無法繼續進行!!!!
rabbitTemplateDirect.convertAndSend(routingKey, object);
是提供給我們的方法,直接發送消息到指定的routing路徑下。
測試類:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:context/applicationContext.xml")
public class MqProducerTest {
@Resource
private MessageProducer messageProducer;
@Test
public void send() {
List<String> list = new ArrayList<>();
list.add("tom");
list.add("jack");
list.add("mark");
String toJson = new Gson().toJson(list);
try {
messageProducer.sendDataToQueue("directExchange","queue1", toJson);
}catch (Exception e){
e.printStackTrace();
}
}
}
我們發送一個list,轉成json發送,執行之後我們就可以去webUI那邊看一下消息是不是發送了。順着Exchange或者Queue都能找到。
2.消費者
想比較與生產者,消費者簡單一些,但是要注意參數!後面會說明。
<?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"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/rabbit http://www.springframework.org/schema/rabbit/spring-rabbit.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<!-- 消息對象json轉換類 -->
<bean id="jsonMessageConverter" class="org.springframework.amqp.support.converter.Jackson2JsonMessageConverter" />
<!-- 配置文件位置 -->
<context:property-placeholder ignore-unresolvable="true" location="classpath*:mq.properties" ignore-resource-not-found="true"/>
<!-- 連接工廠配置 -->
<rabbit:connection-factory id="connectionFactory"
host="${mq.host}"
port="${mq.port}"
username="${mq.username}"
password="${mq.password}"
virtual-host="${mq.vhost}"
publisher-confirms="${mq.publisher-confirms}"
channel-cache-size="${mq.channel-cache-size}"/>
<rabbit:admin connection-factory="connectionFactory"/>
<rabbit:queue name="queue1" durable="true" auto-declare="true"/>
<!-- 監聽器 -->
<rabbit:listener-container connection-factory="connectionFactory" acknowledge="auto">
<rabbit:listener ref="queueListener" method="execute" queue-names="queue1"/>
</rabbit:listener-container>
<!-- 監聽處理 -->
<bean id="queueListener" class="com.george.QueueListener"/>
</beans>
主要看下面,監聽器和監聽處理,這邊可以不繼承提供的接口,我們自己指定接受消息的方法。先看監聽處理,在com.george路徑下創建一個QueueListener類,爲了測試,這個類也是很簡單:
public class QueueListener {
public void execute(String message) throws Exception {
String json = new Gson().toJson(message);
System.out.println(json);
}
}
請注意!!!
剛纔說的參數,這裏設置的方法的參數一定要和發送者返回值相同,所以推薦json格式的string,因爲如果不一致,
將會無法接收到消息!
打印一下,看看效果。
我們寫一個消費者的應用
RabbitApp.java
public class RabbitApp {
private static final Logger logger = LoggerFactory.getLogger(RabbitApp.class);
public static void main(String[] args) {
ClassPathXmlApplicationContext context =
new ClassPathXmlApplicationContext("classpath:context/applicationContext-consumer-mq.xml");
context.start();
System.out.println("rabbit MQ Consumer start");
try {
System.in.read(); // 按任意鍵退出
} catch (IOException e) {
logger.error(e.getMessage());
}
}
}
啓動main方法,如果我們獲取到了消息,證明成功了。
上面是執行消費者成功,下面是獲取到的消息。