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

来源:互联网 发布:mysql忘记root密码重装 编辑:程序博客网 时间:2024/06/03 18:45

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 Queuewriter.send(msg);// Close the connectioncon.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 ConnectionConnection 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 connectioncon.close();


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


0 0