Distributed System: Message (信息传递) and JMI

本文深入探讨了JMI机制的核心概念,包括Message机制的动机、松耦合的优势、JMI中的两种消息风格(Point-to-Point与Publish/Subscribe)、以及如何通过JMI实现不同角色之间的消息传递。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Message机制的动机:


为什么要用Message作为不同的计算机的进程间的通信机制?目的在于——松耦合 (Decoupled)。我们需要一种机制,既能Decoupled in time(即通信的时候,双方不需要同时在线。电话是coupled in time,短信则是decoupled in time),同时也能Decoupled in space(你不需要知道你的通信对象是谁,不需要知道任何关于对方的信息。你只需要知道Message的格式和Message的目的地)。


在Message的JMI机制中,目的地有两种:1)Queue 2)Topic。因为JMI只有两种Message Styles:


Point to Point: 保证消息传输到接受者。




Publish/ Subscribe: 可以设定是否保证消息的有效传输。机制1:没有消费者subscribe(订阅)的话,过了一段时间后这条消息失效。机制2:可以保留这条消息一直到有消费者订阅。




注意,JMI和JDBC一样,都是对不同的实现的抽象。JDBC是对不同的数据库(MySQL/ PostgreSQL等)的抽象方法接口。而JMI是对不同的Message实现(专业术语叫Message Oriented Middleware)的抽象。


已知的MOM有:IBM WebSphere MQ/ Oracle HornetQ and Apache ActiveHQ等。所有的MOM都可以用JMI去操作。而Java EE的GlassFish中也有一个内嵌的MOM,和JMI兼容。


综上所述,JMI机制当中,有三种角色。Client,Destination(Queue/ Topic)和MOM。其中,Queue、Topic属于Adminstrative Resources,由MOM手动创建并实现其底层传输。程序员只需要在控制台手动创建Queue或者Topic,便可利用JMI的Resource lookup的机制实现对Queue的读写。


下面是利用JMI实现对Destination读写的机制总结图:




对应的代码是:


1)Message Production部分:


只有同步的Produce方式。具体代码段如下:


// Lookup the ConnectionFactory using resource injection and assign to cf
@Resource(lookup = "jms/myFactory")
private ConnectionFactory cf;
// lookup the Queue using resource injection and assign to q
@Resource(lookup = "jms/myQueue")
private Queue q;


Connection con = cf.createConnection();
Session session = con.createSession(false, Session.AUTO_ACKNOWLEDGE);

/*
 * You send and receive messages to/from the queue via a session. We
 * want to send, making us a MessageProducer Therefore create a
 * MessageProducer for the session
 */
MessageProducer writer = session.createProducer(q);

/*
 * The message can be text, a byte stream, a Java object, or a
 * attribute/value Map We want to send a text message. BTW, a text
 * message can be a string, or it can be an XML object, and often a
 * SOAP object.
 */
TextMessage msg = session.createTextMessage();
msg.setText(val);

// Send the message to the destination Queue
writer.send(msg);

// Close the connection
con.close();

2)Message Consumer部分。有两种方式,Asynchronous(非同步的)和Synchronous(同步的)。非同步的方法在Java EE当中,可以使用Message Driven Bean(MDB)来实现Asynchronous的方式。非同步的方式指的是:Register as a listener on a Queue or Topic. 


MessageDriven(activationConfig = {
    @ActivationConfigProperty(propertyName = "destinationLookup", propertyValue = "jms/myQueue")
    ,
        @ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Queue")
})

public class MyQueueListener implements MessageListener {
	public MyQueueListener() {
    }
    
    @Override
    public void onMessage(Message message) {
    	try {
	    	if (message instanceof TextMessage) {
	                // Cast it to the right type of message
	                TextMessage tm = (TextMessage) message;
	                // Get the text from the received message
	                String tmt = tm.getText();
	                System.out.println("MyQueueListener received: " + tmt);
	                con.close();
            } else {
                System.out.println("I don't handle messages of this type");
            }
        } catch (JMSException e) {
            System.out.println("JMS Exception thrown" + e);
        } catch (Throwable e) {
            System.out.println("Throwable thrown" + e);
        }
    }
}

同步的方式是:Read and block until message available. (或者没有的话就timeout)


在Java当中,这种方式利用MessageConsumer去实现。


@Resource(lookup = "jms/myFactory")
private ConnectionFactory cf;
// lookup the Queue using resource injection and assign to q
@Resource(lookup = "jms/myQueueTwo")
private Queue q;
// With the ConnectionFactory, establish a Connection, and then a Session on that Connection
Connection con = cf.createConnection();
Session session = con.createSession(false, Session.AUTO_ACKNOWLEDGE);
con.start(); // Be sure to start to connection!
MessageConsumer reader = session.createConsumer(q);
TextMessage tm = null;
while ((tm = (TextMessage) reader.receive(1000)) != null) {
 out.println("<HTML><BODY><H1>Get " + tm.getText() + " from queue</H1>");
 out.println("</BODY></HTML>");
}
// Close the connection
con.close();


MassageConsumer有两种机制确保其是同步的:Blocks forever or wait only for a timeout period. 上述的例子reader.received(1000)就是以1000ms作为timeout period. 


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值