JMS和消息驱动Bean
1.java消息服务(JMS)编程:
应用程序A发送一条消息到消息服务器的某个目的地,然后消息服务器把消息转发给应用程序B,由于JMS允许消息发送方和接收方不同时在线,没有代码关联,从而实现应用程序的解耦,JMS的过程如下:
应用程序A——>消息——>JMS消息服务器——>消息——>应用程序B
2.JMS消息的传递模型:
JMS支持两种消息传递模型:点对点(PTP)、发布订阅(pub/sub)。
(1).PTP:
一条消息只能传递给一个接收方,采用javax.jms.Queue表示。
每个消息被发送到一个特定的消息队列中,接收者从消息队列中获取消息,队列保留着消息直到消息被消费或者超时,当发送时如果接收方不在线,则当接收方上线时还可以接收到消息。
发送者和接收者之间在时间上没有依赖性,即当发送者发送了消息之后,不管接收者是否在运行,都不会影响消息被发送到消息队列,接收者在成功接收消息之后需要向队列应答成功,若希望发送的每条消息都应该被成功接收处理的话,应该使用PTP方式。
(2).pub/sub:
一条消息可以传递给多个接收方,采用javax.jms.Topic表示。
每条消息可以有多个接收者,发布者和订阅者有时间上的依赖性,针对某个主题的订阅者必须创建一个订阅之后才能消费发布者发布的消息,而且为了接收消息,订阅者必须保持运行。发布订阅模式的消息不支持离线消息,即当发生消息时,接收方如果不在线,当接收再次上线时就无法接收到已经发送过的消息。
为了缓和这种严格的时间相关性,jms运行订阅者创建一个可持久化的订阅,这样,即使订阅者没有被激活(运行),也能接收到发布者发布的消息。
若希望发送的消息可以不被做任何处理,或者被一个消费者处理,或者可以被多个消费者处理,应该使用pub/sub模型。
两种消息模型都继承自:javax.jms.Destination类。
3.JMS消息组成:
JMS中一条消息的组成:消息头(header)、属性(property)、消息体(body)。
所有的消息都派生自Message接口,有以下几种类型:
(1).StreamMessage:一种主体中包含java二进制流的消息,其填充和读取均按顺序进行。
(2).MapMessage:一种主体中包含一组键值对的消息,没有定义条目顺序。
(3).TextMessage:一种主体中java字符串的消息(如,普通文本,xml文件等)。
(4).ObjectMessage:一种主体中包含序列化java对象的消息。
(5).ByteMessage:一种主体中包含连续字节流的消息。
4.配置消息到达目标地址(Destination):
消息目标地址是消息发送的目标地址,也是消息接收者获取消息的目标地址,因此在发送jms消息之前,需要先配置消息的目标到达地址。
Jboss中的配置如下:
名称以”**-service.xml”命名,
(1).PTP类型消息目标地址的配置:
<server> <mbean code=”org.jboss.mq.server.jmx.Queue” name=”jboss.mq.destination:service=Queue, name=queue消息的目标地址”> <attribute name=”JNDIName”>queue/ queue消息的目标地址</attribute> <depends optional-attribute-name=”DestinationManager”> Jboss:mq:service=DestinationManager</depends> </mbean> </server>
(2).pub/sub类型消息目标地址的配置:
<server> <mbean code=”org.jboss.mq.server.jmx.Topic” name=”jboss.mq.destination:service=Topic, name=topic消息的目标地址”> <attribute name=”JNDIName”>topic/ topic消息的目标地址</attribute> <depends optional-attribute-name=”DestinationManager”> Jboss:mq:service=DestinationManager</depends> </mbean> </server>
5.发送JMS消息过程:
在java类中发送jms消息一般步骤:
(1).得到一个JNDI初始化上下文:
InitialContext context = new InitialContext();
(2).根据上下文查找JMS连接工厂:
该连接工厂是由JMS提供的,每个javaEE服务器厂商都为它绑定一个全局的JNDI。
以QueueConnectionFactory为例(TopicConnectionFactory类似):
QueueConnectionFactory factory = (QueueConnectionFactory)context.lookup(“ConnectionFacotry”);
(3).从连接工厂得到一个JMS连接:
以QueueConnection(TopicConnection类似)为例:
QueueConnection conn = factory.createQueueConnection();
(4).通过jms连接创建一个jms会话:
以QueueSession(TopicSession类似)为例:
QueueSession session = conn.createQueueSession(false, QueueSession.AUTO_ACKNOWLEDGE);
第一个参数表示:不需要事物。第二个参数表示:自动确认消息已接收的会话。
(5).查找消息目标地址:
Destination destination = (Destination)context.lookup(消息目标地址的JNDI名);
(6).根据会话及目标地址来建立消息生产者:
MessageProducer producer = session.createProducer(destination); TextMessage msg = session.createTextMessage(消息内容); producer.send(msg);
(7).消息发送完毕后,关闭会话和连接:
conn.close(); session.close();
6.使用消息驱动bean(MDB)接收消息:
一个消息驱动bean(MDB)通常要实现MessageListener接口,实现该接口的onMessage(Message message)方法处理接收的jms消息(异步方式接收jms消息)。
在消息驱动bean前加如下注解:
@MessageDriven(activationConfig= { @ActivateConfigProperty(propertyName=”destinationType”, propertyValue=”javax.jms.Queue”), //监听目标地址类型 @ActivateConfigProperty(propertyName=”destination”, propertyValue=”消息的JNDI名称”), //目标地址JNDI名称 @ActivateConfigProperty(propertyName=”acknowledgeNode”, propertyValue=”Auto-acknowledge”) //自动接收消息,默认不用配置 })
由于消息驱动bean使用了实例化池技术,具有处理大批量并发消息的能力,所以非常适合应用在一些网关产品中。
7.JMS编程模型总结:
通过5,6具体学习了JMS发送和接收处理消息的流程后,总结jms编程模型如下:
8.JMS中消息的两种接收方式:
(1).同步方式:订阅者或接收者调用receive方法来接收消息,此方法在接收到消息之前一直阻塞。
(2).异步方式:订阅者或接收者可以注册为一个消息监听器,当消息到达之后,系统自动调用监听器的onMessage方法。