JMS学习笔记总结1

JMS通信模型:

1、  P2P:一个消息只能被一个接收者接收

2、  Publisher/Subscriber:一个消息允许有多个接收者

 

JMS重要概念:

概念

说明

Destination

消息发送的目的地,即Queue或者Topic

Message

消息有以下类型

Stream

Java数据流消息,用标准流操作来顺序的填充和读取

MapStream

一个Map类型的消息,名称为String类型,值为Java的基本类型

TextStream

普通字符串消息

ObjectStream

对象消息,包含一个科序列化的Java对象

BytesStream

二进制数组消息,包含一个byte[]

XMLStream

XML类型的消息

 

最常用的是TextStream和ObjectStream

Session

与JMS提供者建立的会话,通过Session才能建立一个Message

Connection

与JMS提供者建立的会话,通过其才能建立一个Session

ConnectionFactory

通过工厂类才能建立Connection

Producer

消息的生产者,要发送一个消息,必须通过这个生产者来发送

Consumer

消费者,负责接收消息

它们之间的管理

ConnectionFactory---->Connection--->Session--->Message

Destination +Session------------------------------------>Producer

Destination +Session------------------------------------>Consumer

 

 

一个简单JMS例子

import javax.jms.Connection;

import javax.jms.Message;

import javax.jms.MessageConsumer;

import javax.jms.MessageProducer;

import javax.jms.Queue;

import javax.jms.Session;

import javax.jms.TextMessage;

 

import org.apache.activemq.ActiveMQConnectionFactory;

import org.apache.activemq.command.ActiveMQQueue;

 

public class MessageSendAndReceive {

 

    public static void main(String[] args) throws Exception {

        ConnectionFactory factory = new ActiveMQConnectionFactory("vm://localhost");

 

        Connection connection = factory.createConnection();

        connection.start();

     

        Queue queue = new ActiveMQQueue("testQueue");

     

        final Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);

        Message message = session.createTextMessage("Hello JMS!");

     

        MessageProducer producer = session.createProducer(queue);

        producer.send(message);

 

        System.out.println("Send Message Completed!");

     

        MessageConsumer comsumer = session.createConsumer(queue);

        Message recvMessage = comsumer.receive();

        System.out.println(((TextMessage)recvMessage).getText());

    }

 

}

 

MessageListener

 

消费者接收消息的两种方式:

1、  consumer.receive() 或 consumer.receive(int timeout);消费者会阻塞,直到有消息达到或者超时

2、  注册MessageListener;消费者无需等待,可以干自己的事情,当有消息到达时,会调用回调函数onMessage()方法;

注册方法:

MessageConsumer comsumer = session.createConsumer(queue);

 comsumer.setMessageListener(new MessageListener(){

            @Override

            public void onMessage(Message m) {

                TextMessage textMsg = (TextMessage) m;

                try {

                    System.out.println(textMsg.getText());

                } catch (JMSException e) {

                    e.printStackTrace();

                }

            }

         

        });

 

Queue

当有多个消费者在监听同一个Queue时,这些消息者按照先后顺序依次处理队列中的消息。如下例:

import javax.jms.Connection;

import javax.jms.DeliveryMode;

import javax.jms.JMSException;

import javax.jms.Message;

import javax.jms.MessageConsumer;

import javax.jms.MessageListener;

import javax.jms.MessageProducer;

import javax.jms.Queue;

import javax.jms.Session;

import javax.jms.TextMessage;

 

import org.apache.activemq.ActiveMQConnectionFactory;

import org.apache.activemq.command.ActiveMQQueue;

 

 

public class QueueTest {

 

    public static void main(String[] args) throws Exception {

        ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory("vm://localhost");

 

        Connection connection = factory.createConnection();

        connection.start();

     

 

        //创建一个Queue

        Queue queue = new ActiveMQQueue("testQueue");

 

        //创建一个Session

        Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);

     

 

        //注册消费者1

        MessageConsumer comsumer1 = session.createConsumer(queue);

        comsumer1.setMessageListener(new MessageListener(){

            public void onMessage(Message m) {

                try {

                    System.out.println("Consumer1 get " + ((TextMessage)m).getText());

                } catch (JMSException e) {

                    e.printStackTrace();

                }

            }

        });

     

 

        //注册消费者2

        MessageConsumer comsumer2 = session.createConsumer(queue);

        comsumer2.setMessageListener(new MessageListener(){

            public void onMessage(Message m) {

                try {

                    System.out.println("Consumer2 get " + ((TextMessage)m).getText());

                } catch (JMSException e) {

                    e.printStackTrace();

                }

            }

         

        });

     

 

        //创建一个生产者,然后发送多个消息。

        MessageProducer producer = session.createProducer(queue);

        for(int i=0; i<10; i++){

            producer.send(session.createTextMessage("Message:" + i));

        }

    }

 

}

 

  运行这个例子会得到下面的输出结果:

Consumer1 get Message:0

Consumer2 get Message:1

Consumer1 get Message:2

Consumer2 get Message:3

Consumer1 get Message:4

Consumer2 get Message:5

Consumer1 get Message:6

Consumer2 get Message:7

Consumer1 get Message:8

Consumer2 get Message:9

 

  可以看出每个消息直被消费了一次,但是如果有多个消费者同时监听一个Queue的话,无法确定一个消息最终会被哪一个消费者消费。

 

Topic

 

与Queue不同的是,Topic实现的是发布/订阅模型,当发布一条消息时,所有已经订阅了该Topic的订阅者都将收到该信息,将上面例子修改成Topic。

import javax.jms.Connection;  

import javax.jms.JMSException;  

import javax.jms.Message;  

import javax.jms.MessageConsumer;  

import javax.jms.MessageListener;  

import javax.jms.MessageProducer;  

import javax.jms.Session;  

import javax.jms.TextMessage;  

import javax.jms.Topic;  

 

import org.apache.activemq.ActiveMQConnectionFactory;  

import org.apache.activemq.command.ActiveMQTopic;  

 

public class TopicTest {  

 

    public static void main(String[] args) throws Exception {  

        ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory("vm://localhost");  

        Connection connection = factory.createConnection();  

        connection.start();  

        //创建一个Topic  

        Topic topic= new ActiveMQTopic("testTopic");  

        Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);  

        //注册消费者1  

        MessageConsumer comsumer1 = session.createConsumer(topic);  

        comsumer1.setMessageListener(new MessageListener(){  

            public void onMessage(Message m) {  

                try {  

                    System.out.println("Consumer1 get " + ((TextMessage)m).getText());  

                } catch (JMSException e) {  

                    e.printStackTrace();  

                }  

            }  

        });  

        //注册消费者2  

        MessageConsumer comsumer2 = session.createConsumer(topic);  

        comsumer2.setMessageListener(new MessageListener(){  

            public void onMessage(Message m) {  

                try {  

                    System.out.println("Consumer2 get " + ((TextMessage)m).getText());  

                } catch (JMSException e) {  

                    e.printStackTrace();  

                }  

            }  

        });  

        //创建一个生产者,然后发送多个消息。  

        MessageProducer producer = session.createProducer(topic);  

        for(int i=0; i<10; i++){  

            producer.send(session.createTextMessage("Message:" + i));  

        }  

    }  

 

}

运行后得到下面的输出结果:

Consumer1 get Message:0

Consumer2 get Message:0

Consumer1 get Message:1

Consumer2 get Message:1

Consumer1 get Message:2

Consumer2 get Message:2

Consumer1 get Message:3

Consumer2 get Message:3

Consumer1 get Message:4

Consumer2 get Message:4

Consumer1 get Message:5

Consumer2 get Message:5

Consumer1 get Message:6

Consumer2 get Message:6

Consumer1 get Message:7

Consumer2 get Message:7

Consumer1 get Message:8

Consumer2 get Message:8

Consumer1 get Message:9

Consumer2 get Message:9

 

 

 

说明每一个消息都会被所有的消费者消费。

 

 

 

一个消息对象由三个部分组成:消息头(Headers),属性(Properties),消息体(Payload)

消息头

消息头

说明

JMSDestination 

消息的目的地,Topic或者是Queue

JMSDeliveryMode 

消息的发送模式:

persistent: JMS提供者会保持该信息直到该消息被消费者接收,即使其服务关闭,该信息也会保存

nonpersistent:不保存消息,如果服务关闭,消息会被丢失。

可以通过下面的方式设置:

Producer.setDeliveryMode(DeliveryMode.NON_PERSISTENT/ PERSISTENT);

JMSTimestamp

当调用send()方法的时候,JMSTimestamp会被自动设置为当前时间戳,可以通过下面方式得到这个值:

long timestamp = message.getJMSTimestamp();

JMSExpiration

表示一个消息的有效期。只有在这个有效期内,消息消费者才可以消费这个消息。默认值为0,表示消息永不过期。

可以通过下面的方式设置:

producer.setTimeToLive(3600000); //有效期1小时 (1000毫秒 * 60秒 * 60分)

JMSPriority

消息的优先级:0-4为正常的优先级,5-9为高优先级。

可以通过下面方式设置:producer.setPriority(9);

JMSMessageID

一个字符串用来唯一标示一个消息。

JMSReplyTo

有时消息生产者希望消费者回复一个消息,JMSReplyTo为一个Destination,表示需要回复的目的地。当然消费者可以不理会它。

message.setJMSReplyTo(Destination)

JMSCorrelationID

通常用来关联多个Message。例如需要回复一个消息,可以把JMSCorrelationID设置为所收到的消息的JMSMessageID。

JMSType

表示消息体的结构,和JMS提供者有关。

JMSRedelivered

如果这个值为true,表示消息是被重新发送了。因为有时消费者没有确认他已经收到消息或者JMS提供者不确定消费者是否已经收到。

 

 

除了这些Header,消息发送者可以自定义添加一些属性(Properties)。

方法:

TextMessage message = session.createTextMessage("Message payload");

message.setStringProperty("key", “value”);

 

 

 

Selector

 

在JMS中默认创建一个消息消费者的method: sesssion.createConsumer(destination),该消费者将接收destination中的所有消息。

如果想创建一个只关注特定消息的消费者可以使用method:sesssion.createConsumer(destination,selector)

参数:selector是字符串,格式为“key='value'”,key和value可以用户自己定义。该字段用于匹配消息头中的属性。

通过selector可以让特定消费者consumer只接收包含该属性的消息。

 

例子:

注意:该例子在MyEclipse2015+JDK1.7+ActiveMQ5.11.1中验证通过。

package example;

import javax.jms.Connection;

import javax.jms.Destination;

import javax.jms.JMSException;

import javax.jms.Message;

import javax.jms.MessageConsumer;

import javax.jms.MessageListener;

import javax.jms.MessageProducer;

import javax.jms.Queue;

import javax.jms.Session;

import javax.jms.TextMessage;

 

 

import org.apache.qpid.amqp_1_0.jms.impl.ConnectionFactoryImpl;

import org.apache.qpid.amqp_1_0.jms.impl.QueueImpl;

import org.apache.qpid.amqp_1_0.jms.impl.TopicImpl;

 

 

public class JMSSelectorTest {

 

 

public static void main(String[] args) throws Exception {

String user = env("ACTIVEMQ_USER", "admin");

        String password = env("ACTIVEMQ_PASSWORD", "password");

        String host = env("ACTIVEMQ_HOST", "localhost");

        int port = Integer.parseInt(env("ACTIVEMQ_PORT", "5672"));

        String destination = arg(args, 0, "queue://JMSSelectorTestQueue");

 

 

        ConnectionFactoryImpl factory = new ConnectionFactoryImpl(host, port, user, password);

        Destination dest = null;

        if( destination.startsWith("topic://") ) {

            dest = new TopicImpl(destination);

        } else {

            dest = new QueueImpl(destination);

        }

       

        Connection connection = factory.createConnection(user, password);

        connection.start();

 

Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);

MessageConsumer comsumerA = session.createConsumer(dest, "receiver = 'A'");

comsumerA.setMessageListener(new MessageListener() {

public void onMessage(Message m) {

try {

System.out.println("ConsumerA get " + ((TextMessage) m).getText());

} catch (JMSException e1) {

}

}

});

MessageConsumer comsumerB = session.createConsumer(dest, "receiver = 'B'");

comsumerB.setMessageListener(new MessageListener() {

public void onMessage(Message m) {

try {

System.out.println("ConsumerB get " + ((TextMessage) m).getText());

} catch (JMSException e) {

}

}

});

MessageProducer producer = session.createProducer(dest);

for (int i = 0; i < 10; i++) {

String receiver = (i % 3 == 0 ? "A" : "B");

TextMessage message = session.createTextMessage("Message" + i + ", receiver:" + receiver);

message.setStringProperty("receiver", receiver);

producer.send(message);

}

}

 

 

private static String arg(String[] args, int i, String string) {

// TODO Auto-generated method stub

return string;

}

 

 

private static String env(String string, String string2) {

// TODO Auto-generated method stub

return string2;

}

}

 

 

运行程序,console中打印信息:

 

ConsumerA get Message0, receiver:A

ConsumerB get Message1, receiver:B

ConsumerB get Message2, receiver:B

ConsumerA get Message3, receiver:A

ConsumerB get Message4, receiver:B

ConsumerB get Message5, receiver:B

ConsumerA get Message6, receiver:A

ConsumerB get Message7, receiver:B

ConsumerB get Message8, receiver:B

ConsumerA get Message9, receiver:A

ConsumerA get Message0, receiver:A

ConsumerB get Message1, receiver:B

ConsumerB get Message4, receiver:B

ConsumerA get Message6, receiver:A

ConsumerB get Message7, receiver:B

 


--TemporaryQueue和TemporaryTopic

 

TemporaryQueue和TemporaryTopic,从字面上就可以看出它们是“临时”的目的地。可以通过Session来创建,例如:


TemporaryQueue replyQueue = session.createTemporaryQueue();


虽然它们是由Session来创建的,但是它们的生命周期确实整个Connection。如果在一个Connection上创建了两个Session,则一个Session创建的TemporaryQueue或TemporaryTopic也可以被另一个Session访问。那如果这两个Session是由不同的Connection创建,则一个Session创建的TemporaryQueue不可以被另一个Session访问。


另外,它们的
主要作用就是用来指定回复目的地, 即作为JMSReplyTo


在下面的例子中,先创建一个Connection,然后创建两个Session,其中一个Session创建了一个TemporaryQueue,另一个Session在这个TemporaryQueue上读取消息。

 

[java]  view plain copy
  1. import javax.jms.Connection;
    import javax.jms.JMSException;
    import javax.jms.Message;
    import javax.jms.MessageConsumer;
    import javax.jms.MessageListener;
    import javax.jms.MessageProducer;
    import javax.jms.Queue;
    import javax.jms.Session;
    import javax.jms.TemporaryQueue;
    import javax.jms.TextMessage;


    import org.apache.activemq.ActiveMQConnectionFactory;
    import org.apache.activemq.command.ActiveMQQueue;


    public class TemporaryQueueTest {
    public static void main(String[] args) throws Exception {
    ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory("vm://localhost");
    Connection connection = factory.createConnection();
    connection.start();
    Queue queue = new ActiveMQQueue("testQueue2");
    final Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
    // 使用session创建一个TemporaryQueue。
    TemporaryQueue replyQueue = session.createTemporaryQueue();
    TemporaryQueue replyQueue1 = session.createTemporaryQueue();
    System.out.println("replyQueue="+replyQueue+", replyQueue1="+replyQueue1);
    // 接收消息,并回复到指定的Queue中(即replyQueue)
    MessageConsumer comsumer = session.createConsumer(queue);
    comsumer.setMessageListener(new MessageListener() {
    public void onMessage(Message m) {
    try {
    System.out.println("getJMSDeliveryMode: "+((TextMessage) m).getJMSDeliveryMode());
                        System.out.println("getJMSMessageID: "+((TextMessage) m).getJMSMessageID());
                        System.out.println("getJMSTimestamp: "+((TextMessage) m).getJMSTimestamp());
                        System.out.println("getJMSDestination: "+((TextMessage) m).getJMSDestination());
                        System.out.println("getJMSRedelivered: "+((TextMessage) m).getJMSRedelivered());
                        System.out.println("getJMSReplyTo: "+((TextMessage) m).getJMSReplyTo());
                        System.out.println("getJMSPriority: "+((TextMessage) m).getJMSPriority());
                        System.out.println("getJMSType: "+((TextMessage) m).getJMSType());
                        System.out.println("Body: " + ((TextMessage) m).getText());
    System.out.println("Get Message: " + ((TextMessage) m).getText());
    MessageProducer producer = session.createProducer(m.getJMSReplyTo());
    producer.send(session.createTextMessage("ReplyMessage"));
    } catch (JMSException e) {
    }
    }
    });
    // 使用同一个Connection创建另一个Session,来读取replyQueue上的消息。
    // Session session2 = connection.createSession(true,Session.AUTO_ACKNOWLEDGE);
    // Connection connection2 = factory.createConnection(); 
    Session session2 = connection.createSession(true, Session.AUTO_ACKNOWLEDGE);


    MessageConsumer replyComsumer = session2.createConsumer(replyQueue);
    replyComsumer.setMessageListener(new MessageListener() {
    public void onMessage(Message m) {
    try {
    System.out.println("Get reply: " + ((TextMessage) m).getText());
    } catch (JMSException e) {
    }
    }
    });

    MessageProducer producer = session.createProducer(queue);
    TextMessage message = session.createTextMessage("SimpleMessage");
    message.setJMSReplyTo(replyQueue1);
    producer.send(message);
    }
    }

运行结果为: 

replyQueue=temp-queue://ID:NCNL0158-51325-1432865404618-3:1:1, replyQueue1=temp-queue://ID:NCNL0158-51325-1432865404618-3:1:2
getJMSDeliveryMode: 2
getJMSMessageID: ID:NCNL0158-51325-1432865404618-3:1:1:1:1
getJMSTimestamp: 1432865404910
getJMSDestination: queue://testQueue2
getJMSRedelivered: false
getJMSReplyTo: temp-queue://ID:NCNL0158-51325-1432865404618-3:1:2
getJMSPriority: 4
getJMSType: null
Body: SimpleMessage
Get Message: SimpleMessage

:多次创建createTemporaryQueue,仅仅是最后一个数据有差异


如果将: 
Session session2 = connection.createSession(true, Session.AUTO_ACKNOWLEDGE); 
更改为: 
Connection connection2 = factory.createConnection(); 
Session session2 = connection2.createSession(true, Session.AUTO_ACKNOWLEDGE);


就会得到下面的异常: 

Exception in thread "main" javax.jms.InvalidDestinationException: Cannot use a Temporary destination from another Connection
at org.apache.activemq.ActiveMQMessageConsumer.<init>(ActiveMQMessageConsumer.java:196)
at org.apache.activemq.ActiveMQSession.createConsumer(ActiveMQSession.java:1239)
at org.apache.activemq.ActiveMQSession.createConsumer(ActiveMQSession.java:1183)
at org.apache.activemq.ActiveMQSession.createConsumer(ActiveMQSession.java:1095)
at org.apache.activemq.ActiveMQSession.createConsumer(ActiveMQSession.java:1067)
at org.com.activemq1.TemporaryQueueTest.main(TemporaryQueueTest.java:52)

 注:上面例子在Myeclipse2015+JDK1.7+ActiveMQ5.11.1中验证通过。




 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值