1、新建marven項目jms-test
2、在pom.xml導入相關jar包
3、pox.xml配置如下
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.learn.jms</groupId>
<artifactId>jms-test</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>jms-test</name>
<url>http://maven.apache.org</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<org.springframework.version>4.3.12.RELEASE</org.springframework.version>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${org.springframework.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jms</artifactId>
<version>${org.springframework.version}</version>
</dependency>
<dependency>
<groupId>org.apache.activemq</groupId>
<artifactId>activemq-core</artifactId>
<version>5.7.0</version>
<exclusions>
<exclusion>
<artifactId>spring-context</artifactId>
<groupId>org.springframework</groupId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
</project>
4、新建三個資源文件,common.xml,consumer-jms.xml,producer-jms.xml
common.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.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd">
<context:annotation-config/>
<!-- activeMQ 爲我們提供的 ConnectionFactory-->
<bean id="targetConnectionFactory" class="org.apache.activemq.ActiveMQConnectionFactory">
<property name="brokerURL" value="tcp://192.168.3.205:61616"/>
</bean>
<!-- spring jms 爲我們提供的連接池 -->
<bean id="connectionFactory" class="org.springframework.jms.connection.SingleConnectionFactory">
<property name="targetConnectionFactory" ref="targetConnectionFactory"></property>
</bean>
<!-- 一個隊列的目的地 點對點 -->
<bean id="queueDestination" class="org.apache.activemq.command.ActiveMQQueue">
<constructor-arg value="cyc_queue_test"></constructor-arg>
</bean>
<!-- 一個主題的目的地 發佈訂閱 -->
<bean id="topicDestination" class="org.apache.activemq.command.ActiveMQTopic">
<constructor-arg value="cyc_topic_test"></constructor-arg>
</bean>
</beans>
consumer-jms.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.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd">
<!-- 導入公共配置 -->
<import resource="common.xml"/>
<!-- 配置消息監聽器 -->
<bean id="consumerMessageListener" class="com.learn.jms.consumer.ConsumerMessageListener"></bean>
<!-- 配置消息監聽容器 -->
<bean id="jmsContainer" class="org.springframework.jms.listener.DefaultMessageListenerContainer">
<property name="connectionFactory" ref="connectionFactory"></property>
<!-- <property name="destination" ref="queueDestination"></property> -->
<property name="destination" ref="topicDestination"></property>
<property name="messageListener" ref="consumerMessageListener"></property>
</bean>
</beans>
producer-jms.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.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd">
<!-- 導入公共配置 -->
<import resource="common.xml"/>
<bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate">
<property name="connectionFactory" ref="connectionFactory"></property>
</bean>
<bean class="com.learn.jms.producer.ProducerServiceImpl"></bean>
</beans>
5、新建生產者包com.learn.jms.producer
6、接口:ProducerService
package com.learn.jms.producer;
public interface ProducerService {
/**
* 發送消息
* @param message
*/
void sendMessage(String message);
}
7、生產者實現類ProducerServiceImpl
package com.learn.jms.producer;
import javax.annotation.Resource;
import javax.jms.Destination;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.Session;
import javax.jms.TextMessage;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jms.core.JmsTemplate;
import org.springframework.jms.core.MessageCreator;
public class ProducerServiceImpl implements ProducerService {
@Autowired
JmsTemplate jmsTemplate;
@Resource(name = "topicDestination")
// @Resource(name = "queueDestination")
Destination destination;
@Override
public void sendMessage(final String message) {
//使用jmsTemlate 發送消息
jmsTemplate.send(destination,new MessageCreator() {
//創建一個消息
@Override
public Message createMessage(Session session) throws JMSException {
TextMessage textMessage = session.createTextMessage(message);
return textMessage;
}
});
System.out.println("【發送消息】Message:"+message);
}
}
8、生產者生產消息測試類AppProducer
package com.learn.jms.producer;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class AppProducer {
public static void main(String[] args) {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring/producer-jms.xml");
ProducerService producerService = context.getBean(ProducerService.class);
for (int i = 0; i < 10; i++) {
producerService.sendMessage("test"+i);
}
context.close();
}
}
9、新建消費者包com.learn.jms.consumer
10、消費者監聽器ConsumerMessageListener
package com.learn.jms.consumer;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageListener;
import javax.jms.TextMessage;
public class ConsumerMessageListener implements MessageListener{
@Override
public void onMessage(Message message) {
TextMessage textMessage = (TextMessage) message;
try {
System.out.println("接受消息"+textMessage.getText());
} catch (JMSException e) {
e.printStackTrace();
}
}
}
11、消費者接受消息測試
package com.learn.jms.consumer;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class AppConsumer {
public static void main(String[] args) {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring/consumer-jms.xml");
// ConsumerMessageListener producerService = context.getBean(ConsumerMessageListener.class);
}
}
隊列(Queue)和主題(Topic)是JMS支持的兩種消息傳遞模型:
1、點對點(point-to-point,簡稱PTP)Queue消息傳遞模型:
通過該消息傳遞模型,一個應用程序(即消息生產者)可以向另外一個應用程序(即消息消費者)發送消息。在此傳遞模型中,消息目的地類型是隊列(即Destination接口實現類實例由Session接口實現類實例通過調用其createQueue方法並傳入隊列名稱而創建)。消息首先被傳送至消息服務器端特定的隊列中,然後從此對列中將消息傳送至對此隊列進行監聽的某個消費者。同一個隊列可以關聯多個消息生產者和消息消費者,但一條消息僅能傳遞給一個消息消費者。如果多個消息消費者正在監聽隊列上的消息,,JMS消息服務器將根據“先來者優先”的原則確定由哪個消息消費者接收下一條消息。如果沒有消息消費者在監聽隊列,消息將保留在隊列中,直至消息消費者連接到隊列爲止。這種消息傳遞模型是傳統意義上的懶模型或輪詢模型。在此模型中,消息不是自動推動給消息消費者的,而是要由消息消費者從隊列中請求獲得。
2、發佈/訂閱(publish/subscribe,簡稱pub/sub)Topic消息傳遞模型:
通過該消息傳遞模型,應用程序能夠將一條消息發送給多個消息消費者。在此傳送模型中,消息目的地類型是主題(即Destination接口實現類實例由Session接口實現類實例通過調用其createTopic方法並傳入主題名稱而創建)。消息首先由消息生產者發佈至消息服務器中特定的主題中,然後由消息服務器將消息傳送至所有已訂閱此主題的消費者。主題目標也支持長期訂閱。長期訂閱表示消費者已註冊了主題目標,但在消息到達目標時該消費者可以處於非活動狀態。當消費者再次處於活動狀態時,將會接收該消息。如果消費者均沒有註冊某個主題目標,該主題只保留註冊了長期訂閱的非活動消費者的消息。與PTP消息傳遞模型不同,pub/sub消息傳遞模型允許多個主題訂閱者接收同一條消息。JMS一直保留消息,直至所有主題訂閱者都接收到消息爲止。pub/sub消息傳遞模型基本上是一個推模型。在該模型中,消息會自動廣播,消息消費者無須通過主動請求或輪詢主題的方法來獲得新的消息。
具體區別對比如下:
類型 | Topic | Queue |
概要 | Publish Subscribe messaging 發佈訂閱消息 | Point-to-Point 點對點 |
有無狀態 | topic數據默認不落地,是無狀態的。 | Queue數據默認會在mq服務器上以文件形式保存,比如Active MQ一般保存在$AMQ_HOME\data\kr-store\data下面。也可以配置成DB存儲。 |
完整性保障 | 並不保證publisher發佈的每條數據,Subscriber都能接受到。 | Queue保證每條數據都能被receiver接收。 |
消息是否會丟失 | 一般來說publisher發佈消息到某一個topic時,只有正在監聽該topic地址的sub能夠接收到消息;如果沒有sub在監聽,該topic就丟失了。 | Sender發送消息到目標Queue,receiver可以異步接收這個Queue上的消息。Queue上的消息如果暫時沒有receiver來取,也不會丟失。 |
消息發佈接收策略 | 一對多的消息發佈接收策略,監聽同一個topic地址的多個sub都能收到publisher發送的消息。Sub接收完通知mq服務器 | 一對一的消息發佈接收策略,一個sender發送的消息,只能有一個receiver接收。receiver接收完後,通知mq服務器已接收,mq服務器對queue裏的消息採取刪除或其他操作。 |