您的位置:首页 > 编程语言 > Java开发

JMS学习心得(一)

2009-07-22 15:17 246 查看
学习中的一些心得记录
p2p方式:

概念:queue,QueueSender,QueueReceiver,队列,消息发送者,消息接收者三个角色。发送者向队列中加入消息,接收者从队列取出消息,队列中的消息接收一条少一条,如果有多个接收者连接到队列,一条消息只能被一个接收者取走。

一、
消息发送方式默认不设置的时候是  DeliveryMode.PERSISTENT
方式,也就是持久化方式。该常量值为2。这种方式消息不会丢失,会保存在服务器上。就是说消息发送后,即使你关闭jms服务器(比如用activeMQ,
关闭服务器程序),然后服务重新启动后,这条消息仍然是存在的,而其他使用NON_PERSISTENT方式的消息就丢失了。我想大多数情况下啊我们需要
的是PERSISTENT方式吧!

DeliveryMode.NON_PERSISTENT 常量值为1

DeliveryMode.PERSISTENT 常量值为2

int a = msgp0.getDeliveryMode();

        //msgp0.setDeliveryMode(DeliveryMode.PERSISTENT);

二、消息的消费者接收消息可以采用两种方式:

1、consumer.receive() 或 consumer.receive(int timeout);

2、注册一个MessageListener。

采用第一种方式,即同步方式,遇到receive方法就会阻塞,消息的接收者会一直等待下去,直到有消息到达,或者超时。该方式调用一次方法只接收一条消息。

采用第二种方式,即异步方式,程序会一直监听,只要有消息就会响应onMessage方法,当执行
conn.close()方法时会结束监听器。
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();

                }

            }

           

        });

测试发现
conn.close()
方法对这两种方式有些不同,对于监听器方式,只要close方法执行,监听就会终止,估计监听是以后台线程方式执行的。而对于recive接收方式,只要
receive方法只要调用一次,就必须等到有消息到达才会执行下面的语句,是阻塞的方式,即使后面的conn.close()不会执行到。

参考:http://www.cnblogs.com/iloveu/archive/2009/06/10/1500714.html

pub/sub方式


概念:topic,publisher,subscriber,主题,发布者,订阅者三个角色。主题和订阅者是一对多关系,一个主题可以被多个订阅者订阅。当发布者向某个主题发送一条消息时,所有的订阅者都会收到。

如何理解订阅的概念呢,个人理解,分两种情况:

一、
创建一个订阅者时使用session.createDurableSubscriber(topic, clientId
)方法创建为持久型订阅者时,该topic和clientId的订阅关系将被保存在服务器上,即产生了订阅关系。这样clientId这个id的订阅者将
在离线的时候,也不会丢失消息。这个订阅关系也可以理解为被持久化在jms服务器上了,使用jmx的监视控制台(我使用的activeMq),可以看到有
一个Subscription的节点,下面有你订阅主题时给定的客户端名字。可以使用unsubscribe
方法
取消订阅关系。

二、
创建一个非持久化方式的订阅者时,只有在客户端订阅者连接到jms服务器时,订阅关系成立,订阅者离线时,订阅关系即取消,不会保存在服务器上,这也是非
持久化方式订阅者不能离线接收消息的原因吧。默认为广播方式,在没有订阅者连接到服务器时,发送的消息将丢失,不会保存在服务器。

对jms规范的理解:

jms
规范是sun提出的java的消息服务统一的api接口规范,规范、标准的好处就不用说了,java能走到今天,规范标准的制定可以说有很大的功劳吧。所
有提供java消息服务的软件提供者都必须针对这个接口实现。我们编写jms程序时,基本可以做到只针对接口编程,不用考虑是那个厂家实现,这是我们的代
码有了很大的灵活行,不绑定某个具体厂商。只要你的代码写的够好,完全可以不修改代码就直接部署到不同厂商的jms服务器上。

举个例子:编写一个基于ActiveMQ的jms程序时有这样的代码:

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

...

Queue queue = new
 ActiveMQQueue("testQueue"
); 

等,这样就在代码里绑死了ActiveMQ的api。要做到厂商无关性,应该使用jndi来取得工厂对象以及队列资源。

比如:

ConnectionFactory cf = (ConnectionFactory) ctx.lookup("connectionFactory");

...

Destination dest = (Queue) ctx.lookup("MyQueue");

注意接口也尽量使用jms的大的接口。当然这里需要提供jndi服务支持,ActiveMQ本身提供jndi服务,只要在classpath中有一个jndi.properties文件,在配置文件中对资源做一些配置就可以了

比如:

java.naming.factory.initial = org.apache.activemq.jndi.ActiveMQInitialContextFactory

connectionFactoryNames = connectionFactory, queueConnectionFactory, topicConnectionFactry

queue.MyQueue = zmQueue

topic.MyTopic = zmTopic

等。

对jms规范1.1的一些理解:

JMS 1.0.2 定义了两种类型的消息传递域(它们是相互独立的),即点对点和发布/订阅。JMS 的最新版本,即版本 1.1,JMS 统一了这两个域。如下图:有了 JMS 1.1,客户机就不再必须专门针对这个或那个域进行实现了。

JMS 公共

PTP 域

Pub/Sub 域

ConnectionFactoryQueueConnectionFactoryTopicConnectionFactory
ConnectionQueueConnectionTopicConnection
DestinationQueueTopic
SessionQueueSessionTopicSession
MessageProducerQueueSenderTopicPublisher
MessageConsumerQueueReceiverTopicSubscriber
参考:http://www.ibm.com/developerworks/cn/java/j-jms11/index.html

就是说,只使用JMS公共域的接口就可以完成jms程序编写。所以推荐尽量使用大的接口,增加代码的灵活性。

比如,写pub/sub方式的消息程序也可以这样:

        Context ctx = new InitialContext();

        ConnectionFactory factory = (ConnectionFactory) ctx

                .lookup("connectionFactory");

        Connection connection = factory.createConnection();

        connection.start();

        // 创建一个Topic

        Destination topic = (Destination) ctx.lookup("MyTopic");

        Session session = connection.createSession(false,

                Session.AUTO_ACKNOWLEDGE);

        MessageConsumer comsumer3 = session.createConsumer(topic);

        Message msg = comsumer3.receive();
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息