JMS基础

来源:互联网 发布:最好的工业设计软件 编辑:程序博客网 时间:2024/05/22 13:13
1. JMS基础
JMS(Java Message Service)是由Sun开发的一套API,它为开发者提供了一套访问MOM(Message-Oriented Middleware)的标准方法。MOM是消息接收/转发的服务器,它能对消息进行缓存或持久操作,保证消息的安全性。开发者以松耦合的方式集成不同应用程序,无须了解远程过程调用(RPC)和网络/通信协议的细节。
1.1 两种消息类型
PTP:一条消息只能被一个消费者取走,且从队列中移除;
Pub/Sub:发布消息给所有订阅者,其都有处理每一条消息的机会;
1.2 重要接口
ConnectionFactory
Connection
Destination
Session
MessageProducer
MessageConsumer
一个JMS程序典型步骤:
     通过JNDI查询ConnectionFactory-->用ConnectionFactory创建一个Connection-->用Connection创建一个或多个Session-->通过JNDI查询一个或多个Destination-->用Session和Destination创建对应的MessageProducer和MessageConsumer-->启动Connection-->通过JMS API的调用将消息发送到MOM,或者从MOM取回并处理消息。
1.3 消息结构
Header
Properties
Body:TextMessage/ObjectMessage/MapMessage/BytesMessage/StreamMessage
1.4 消息收发机制
JMS事务:类似数据库的事务管理
消息确认:接收着在成功收到消息后,将一个回执发送给MOM
   Session.AUTO_ACKNOWLEDGE:在完成接收消息时,Session自动发送一个确认回执;
   Session.CLIENT_ACKNOWLEDGE:由客户端程序手工调用Message#acknowledge()方法显示确认消息接收;
   Session.DUPS_OK_ACKNOWLEDGE:延迟发送,提高接收性能。不过MOM宕机后可能重复发送给客户端。
Connection在创建Session时必须指定消息确认方式,下例为创建一个不需要事务、自动确认回执的Session。
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
消息选择:基于SQL92的子集,对应WHERE部分的过滤表达式。选择条件通过Header字段和Properties属性进行匹配度设置,Body内的值不能用于选择条件。
e.g.
根据Header中的JMSType字段以及Properties中的color和weight属性进行过滤:
MessageConsumer con = session.createConsumer(destination, "JMSType='car' AND color='blue' and weight>25")
1.5 发送消息
JMS规范要求ConnectionFactory和Destination必须从JNDI中获取,这也说明在一般情况下,JMS客户端必须绑定在应用服务器上。

public void send(TextMessage msgText){
    Connection connection = null;
    try {
        InitialContext ctx = new InitialContext();
        ConnectionFactory factory = (ConnectionFactory) ctx.lookup("jndi/jmsConn");
        connection = factory.createConnection();
        Destination dest = (Destination) ctx.lookup("jndi/dest");
        Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
        MessageProducer sender = session.createProducer(dest);
        sender.send(msgText);
    } catch (NamingException e) {
        e.printStackTrace();
    } catch (JMSException e) {
        e.printStackTrace();
    } finally{
        try {
            connection.close();
        } catch (JMSException e) {
            e.printStackTrace();
           }
       }
}

1.6 接收消息

同步接收:MessageConsumer#receive(),当目标地址中没有消息时,主程序阻塞,也可以设定超时时间。

异步接收:向MessageConsumer注册一个MessageListener,在注册之前必须先将Connection启动,Connection#start(),MessageConsumer#setMessageListener(this)。

   void onMessage(Message message);

Note:发送或接收完消息,必须断开连接!

2. 消息重复接收问题

问题:客户端接收地址消息-->MOM因故障关闭-->客户端发送回执消息失败-->MOM重启-->客户端再次接收同一条消息

Solution1:采用JTA全局事务,将数据库操作和JMS操作纳入到同一个全局事务,但这也性能影响很大;

Solution2:客户端自身提供消息重复性检查功能,接收消息后进行消息处理的逻辑仅工作在本地数据源事务中。