JMS是java的消息服务,JMS的客户端直接可以通过JMS服务进行异步的消息传递,JMS支持两种消息模型,Point-to-Point(p2p)和Public/Subsribe(Pub/Sub),即点对点和发布订阅模型。
在JSM中,消息的产生和消费是异步的,对于消费来说,JSM的消费者可以通过两种方式来消费消息。
- 同步-订阅者或接收者调用receve方法来接受消息,receive方法在能够接受到消息之前(或超时之前)将一直阻塞。
- 异步 订阅者或者接收者可以注册为一个消息监听器,当消息到达之后,系统自动调用监听器的onMessage方法。
消息驱动Bean(MDB)是基于JMS的。MDB就是异步消息的消费者,当消息到达之后,由容器负责调用MDB,客户端发送消息到destination,MDB作为一个MessageListener接收消息。
P2P
在p2p模型中,有下列概念:消息队列(queue),发送者(sender),接受者(Reveiver)。没个消息都被发送到一个特定的队列,接收者从队列中获取消息,队列保留着消息,直到他们被消费或超时。
- 每个消息只有一个消费者,一旦被消费,消息就不再消息队列中。
- 发送者和接收者之间在时间上没有依赖性,也就是说当发送者发送了消息之后,不管接收者有没有正在运行,它不会影响到消息发送到队列。
- 接收者在成功接收消息之后需向队列应答成功。
- 如果需要发送的每个消息都被成功处理,需要P2P模型。
编程模型
接收者
package com.roy.ejb;
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/myqueue")
}
)
public class MyQueueMDBBean implements MessageListener {
public void onMessage(Message msg) {
try {
TextMessage textMessage = (TextMessage)msg;
System.out.println("MyMDBBean被调用了! [" + textMessage.getText() +"]");
} catch (JMSException e) {
e.printStackTrace();
}
}
}
发送者
package com.roy.ejb;
import javassist.CtClass;
import javax.jms.Queue;
import javax.jms.QueueConnection;
import javax.jms.QueueConnectionFactory;
import javax.jms.QueueSender;
import javax.jms.QueueSession;
import javax.jms.Session;
import javax.jms.TextMessage;
import javax.naming.InitialContext;
import org.jboss.ejb3.MCKernelAbstraction.AlreadyInstantiated.Factory;
import com.sun.xml.bind.CycleRecoverable.Context;
/**
* @author yiqing
*
*/
public class MyQueueMDBBeanClient {
/**
* @param args
* @throws JMSException
*/
public static void main(String[] args) throws Exception {
InitialContext ctx = new InitialContext();
//获取ConnectionFactory
QueueConnectionFactory factory = (QueueConnectionFactory)ctx.lookup("ConnectionFactory");
//创建QueueConnection对象
QueueConnection connection = factory.createQueueConnection();
//创建QueueSession对象,第一个参数表示事务自动提交,第二个参数标识一旦消息被正确送达,将自动发回响应
QueueSession session = connection.createQueueSession(false, QueueSession.AUTO_ACKNOWLEDGE);
//获取Destination对象
Queue queue = (Queue)ctx.lookup("queue/myqueue");
//创建文本消息
TextMessage msg = session.createTextMessage("世界,你好");
//创建发送者
QueueSender sender = session.createSender(queue);
//发送信息
sender.send(msg);
//关闭会话
session.close();
System.out.println("消息已经发送");
}
}
PUB/SUB
在Pub/Sub模型中,有下列概念:主题(Topic),发布者(Publisher),订阅者(Subscriber),客户端将消息发送到主题,多个发布者将消息发送到Topic,系统将这些消息传递给多个订阅者。
- 每个消息可以有多个消费者
- 发布者和订阅者之间有时间上的依赖性,针对某个主题的订阅者,它必须创建一个订阅之后,才能消费发布者的消息,而且,为了消费消息,订阅者必须保持。
- 如果希望发送到消息可以不被任何处理,可以采用PUB/SUB模型。
订阅者
package com.roy.ejb;
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/mytopic")
}
)
public class MyTopicMDBBean implements MessageListener {
public void onMessage(Message msg) {
try {
TextMessage textMessage = (TextMessage)msg;
System.out.println("MyTopicMDBBean被调用了! [" + textMessage.getText() +"]");
} catch (JMSException e) {
e.printStackTrace();
}
}
}
发布者
package com.roy.ejb;
import javassist.CtClass;
import javax.jms.Topic;
import javax.jms.TopicConnection;
import javax.jms.TopicConnectionFactory;
import javax.jms.TopicPublisher;
import javax.jms.TopicSession;
import javax.jms.Session;
import javax.jms.TextMessage;
import javax.naming.InitialContext;
import org.jboss.ejb3.MCKernelAbstraction.AlreadyInstantiated.Factory;
import com.sun.xml.bind.CycleRecoverable.Context;
/**
* @author yiqing
*
*/
public class MyTopicMDBBeanClient {
/**
* @param args
* @throws JMSException
*/
public static void main(String[] args) throws Exception {
InitialContext ctx = new InitialContext();
//获取ConnectionFactory
TopicConnectionFactory factory = (TopicConnectionFactory)ctx.lookup("ConnectionFactory");
//创建Connection对象
TopicConnection connection = factory.createTopicConnection();
//创建Session对象,第一个参数表示事务自动提交,第二个参数标识一旦消息被正确送达,将自动发回响应
TopicSession session = connection.createTopicSession(false, TopicSession.AUTO_ACKNOWLEDGE);
//获取Destination对象
Topic topic = (Topic)ctx.lookup("topic/mytopic");
//创建文本消息
TextMessage msg = session.createTextMessage("世界,你好");
//创建发布者
TopicPublisher publisher = session.createPublisher(topic);
//发布信息
publisher.publish(msg);
//关闭会话
session.close();
System.out.println("消息已经发布");
}
}
总之,JMS有两种方式:1.P2P这种方式发送的消息每个消息都会被成功处理。2.PUB/SUB这种方式发送的消息可以不全部处理。