java消息服務(簡稱JMS)是用於訪問企業消息系統的開發商中立的API。企業消息系統可以協助應用軟件通過網絡進行消息交互。
JMS的編程過程很簡單,概括爲:應用程序A發送一條消息到消息服務器的某個目的地(Destination),然後消息服務器把消息轉發給應用程序B。因爲應用程序A和應用程序B沒有直接的代碼關聯,所以兩者實現瞭解耦。
消息有下面幾種類型,他們都是派生自Message接口。
StreamMessage:一種主體中包含Java基元值流的消息。其填充和讀取均按順序進行。
MapMessage:一種主體中包含一組名-值對的消息。沒有定義條目順序。
TestMessage:一種主體中包含Java字符串的消息。
ObjectMessage:一種主體中包含序列化Java對象的消息。
ByteMessage:一種主體中包含連續字節流的消息。
JMS支持兩種消息傳遞模型:點對點(point-to-point,簡稱PTP)和發佈/訂閱(publish/subscribe,簡稱pub/sub)。這兩種消息傳遞模型非常相似,但有以下區別:
PTP消息傳遞模型規定了一條消息只能傳遞給一個接收方。採用javax.jms.Queue表示。
Pub/sub消息傳遞模型允許一條消息傳遞給多個接收方。採用javax.jms.Topic表示。
這兩種模型都通過擴展公用基類來實現。例如javax.jms.Queue和javax.jms.Topic都擴展自javax.jms.Destination類。
一、配置消息到達的目標地址,創建xml文件,文件名後綴必須是 -service.xml(例如 jsmMessage-service.xml)
<?xml version="1.0" encoding="UTF-8"?>
<server>
<!-- Queue類型 -->
<mbean code="org.jboss.mq.server.jmx.Queue"
name="jboss.mq.destination:service=Queue,name=jmsMessageQueue">
<attribute name="JNDIName">queue/jmsMessageQueue</attribute>
<depends optional-attribute-name="DestinationManager">jboss.mq:service=DestinationManager</depends>
</mbean>
<!-- Topic類型 -->
<mbean code="org.jboss.mq.server.jmx.Topic"
name="jboss.mq.destination:service=Topic,name=jmsMessageTopic">
<attribute name="JNDIName">topic/jmsMessageTopic</attribute>
<depends optional-attribute-name="DestinationManager">jboss.mq:service=DestinationManager</depends>
</mbean>
</server>
二、建立消息發送者
Queue類型發送者
package com.jms;
import java.util.Properties;
import javax.jms.Destination;
import javax.jms.MessageProducer;
import javax.jms.QueueConnection;
import javax.jms.QueueConnectionFactory;
import javax.jms.QueueSession;
import javax.naming.InitialContext;
public class QueueSender {
/**
* Queue實現了負載均衡,一個消息只能被一個消費者接受,當沒有消費者可用時,這個消息會被保存直到有 一個可用的消費者,
* 一個queue可以有很多消費者,他們之間實現了負載均衡,所以Queue實現了一個可靠的JMS負載均衡。
*/
public static void main(String[] args) {
try {
Properties props = new Properties();
//jboss所用的JNDI
props.setProperty("java.naming.factory.initial", "org.jnp.interfaces.NamingContextFactory");
props.setProperty("java.naming.provider.url", "localhost:1099");
InitialContext ctx = new InitialContext(props);
//根據上下文查找一個連接工廠
QueueConnectionFactory factory = (QueueConnectionFactory) ctx.lookup("QueueConnectionFactory");
//創建一個連接
QueueConnection con = factory.createQueueConnection();
//創建一個會話
QueueSession session = con.createQueueSession(false, QueueSession.AUTO_ACKNOWLEDGE);
//獲得目標地址
Destination distination = (Destination) ctx.lookup("queue/jmsMessageQueue");
//根據會話和目標地址來創建消息發送者
MessageProducer producer = session.createProducer(distination);
producer.send(session.createTextMessage("你好,傳智播客,我是queue消息"));
session.close();
con.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
Topic類型發送者package com.jms;
import java.util.Properties;
import javax.jms.Destination;
import javax.jms.MessageProducer;
import javax.jms.TopicConnection;
import javax.jms.TopicConnectionFactory;
import javax.jms.TopicSession;
import javax.naming.InitialContext;
public class TopicSender {
/**
* TOPIC實現了分發和訂閱,當你分發一個消息,所有訂閱這個消息的服務都能得到這個服務,
* 所以從0到許多個訂閱者都能得到一個消息的拷貝,只有在消息代理收到消息時有一個有效訂閱時的訂閱者才能得到這個消息的拷貝。
*/
public static void main(String[] args) {
try {
Properties props = new Properties();
//jboss所用的JNDI
props.setProperty("java.naming.factory.initial", "org.jnp.interfaces.NamingContextFactory");
props.setProperty("java.naming.provider.url", "localhost:1099");
InitialContext ctx = new InitialContext(props);
//根據上下文查找一個連接工廠
TopicConnectionFactory factory = (TopicConnectionFactory) ctx.lookup("TopicConnectionFactory");
//創建一個連接
TopicConnection con = factory.createTopicConnection();
//創建一個會話
TopicSession session = con.createTopicSession(false, TopicSession.AUTO_ACKNOWLEDGE);
//獲得目標地址
Destination distination = (Destination) ctx.lookup("topic/jmsMessageTopic");
//根據會話和目標地址來創建消息發送者
MessageProducer producer = session.createProducer(distination);
producer.send(session.createTextMessage("你好,傳智播客,我是topic消息"));
session.close();
con.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
三、採用消息驅動Bean(Message Driven Bean)接收消息。一個MDB通常要實現MessageListener接口,該接口定義了onMessage( )方法。Bean通過它來處理接收到的JMS消息。
Queue類型接收者
package com.bean;
import javax.ejb.ActivationConfigProperty;
import javax.ejb.MessageDriven;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageListener;
import javax.jms.TextMessage;
@MessageDriven(activationConfig = {
@ActivationConfigProperty(propertyName="destinationType",propertyValue="javax.jms.Queue"),
@ActivationConfigProperty(propertyName="destination",propertyValue="queue/jmsMessageQueue")
})
public class QueueMessageDriverBean implements MessageListener{
@Override
public void onMessage(Message message) {
TextMessage msg = (TextMessage) message;
try {
System.out.println("Queue = " +msg.getText());
} catch (JMSException e) {
e.printStackTrace();
}
}
}
Topic類型接收者
package com.bean;
import javax.ejb.ActivationConfigProperty;
import javax.ejb.MessageDriven;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageListener;
import javax.jms.TextMessage;
@MessageDriven(activationConfig = {
@ActivationConfigProperty(propertyName="destinationType",propertyValue="javax.jms.Topic"),
@ActivationConfigProperty(propertyName="destination",propertyValue="topic/jmsMessageTopic")
})
public class TopicMessageDriverBean1 implements MessageListener{
@Override
public void onMessage(Message message) {
TextMessage msg = (TextMessage) message;
try {
System.out.println("Topic = " + msg.getText());
} catch (JMSException e) {
e.printStackTrace();
}
}
}