1. 介绍
JMS((Java Message Service:Java消息服务)也是JavaEE很重要的标准之一,企业应用组件互相需要通讯,就引出了面向消息的模式来进行消息互通。基于消息服务的方式不需要消息发送方与消息接收方进行任何的耦合,甚至可以不需要知道彼此的存在。这种通讯方式既可以是同步的、也可以是异步的(因业务需求不同开发者可自己定制)。官方的解释如下:
JMS是一种与厂商无关的 API,用来访问消息收发系统。它类似于 JDBC(Java Database Connectivity):这里,JDBC 是可以用来访问许多不同关系数据库的 API,而 JMS 则提供同样与厂商无关的访问方法,以访问消息收发服务。许多厂商目前都支持 JMS,包括 IBM 的 MQSeries、BEA的 Weblogic JMS service和 Progress 的 SonicMQ,这只是几个例子。 JMS 使您能够通过消息收发服务(有时称为消息中介程序或路由器)从一个 JMS 客户机向另一个 JML 客户机发送消息。消息是 JMS 中的一种类型对象,由两部分组成:报头和消息主体。报头由路由信息以及有关该消息的元数据组成。消息主体则携带着应用程序的数据或有效负载。根据有效负载的类型来划分,可以将消息分为几种类型,它们分别携带:简单文本 (TextMessage)、可序列化的对象 (ObjectMessage)、属性集合 (MapMessage)、字节流 (BytesMessage)、原始值流 (StreamMessage),还有无有效负载的消息 (Message)。 |
实际上读者可以把JMS当做“QQ”,每个QQ使用人可以当做企业中的一个小组件,其中一个人A君具备查询大量数据的功能,另一个人B君具备破解密码的功能。能解码的人需要能查询大量数据的人提供查询数据的服务。这个时候B君就用QQ和A君通讯:“嗨,哥们,给我一个密码的密文,我来破解!”,消息发到QQ服务器,通过网络传输将此消息传达给A君,A君收到消息后开始工作,将查询结果return给服务器,服务器再将return的结果传给了B君,B君拿到密文结果后接下来自己再工作。
以上是一个同步消息的例子,没有反馈的密文,B君无法进行下一步的工作,他会一直等待A君给他的反馈。
如果B君下一步的工作不是严格依赖于A君的反馈信息,则完全可以采用异步的方式进行消息的传输。比如B君可以这样发消息说:“我要自己破解手中已经收到的一个密文了啊,哥们,如果你在线,给我一个回复就行!一会儿可能需要您的配合……”。
这样即使A君不在线,没收到这个消息,也不会影响B君下一步的工作执行。
2. 角色说明
JMS分为3个角色
1. JMS消息生产者:顾名思义,一个消息的发起者
2. JMS消息的消费者:顾名思义,这个消息的实际读取、处理者
3. JMS消息服务器:路由来自各方的JMS消息的服务器,通常也就是指着应用服务器,比如Weblogic、JBoss等都提供了JMS消息服务支持。另外,JMS生产者都是将消息发送到一个目的地、消息消费者也是从该目的地去取得消息。这个目的地也就是在应用服务器上。JMS消息也是通过应用服务器这个“中介公司”传达的。
由此看来,JMS的消息规范体系和QQ的信息原理更加吻合了。
3. 发送与消费方式
点对点PTP方式:
咱们还是拿QQ来举例子,这种方式就好比上面的例子,一个人和另一个人进行单一的通讯,除了服务器负责转发、路由消息,其他消息消费者不会接收该消息。只有消息目的消费者才能收到此消息。
发布/订阅Pub-Sub方式:
这个就好比一个人往QQ群发送一个消息,所有在这个群中、并且当时在线的人都会接收到来自群里的消息。当然了这里所说的订阅就是表示在群中的人。
实际上在JMS1.1规范推出后,给使用者的感觉,起码在编程上PTP方式和Pub-Sub方式差不太多,对于使用者除了在应用服务器中配置的消息目的地有些差异之外,其他并没太感觉有太大差异(底层会做出区分,根据不同类型的消息会自动调用不同类型的API,典型的多态)。
统一的API接口如下:
JMS1.1接口 |
|
连接工厂接口 |
ConnectionFactory |
JMS连接接口 |
Connection |
会话接口 |
Session |
消息目的接口 |
Destination |
消息生产者接口 |
MessageProducer |
消息消费者接口 |
MessageConsumer |
4. 示例代码
1.PTP消息
可以看到我配置了一个目的叫做jbossJMS的Resource,那我们就可以往这个消息目的发送JMS消息,并且可以从这个JMS目的消费消息了。
咱们先看消费者代码,当然也应该是先执行消费者代码,等消息生产者生产消息的时候,消费者才能见听到。
package jms.ptp;
import java.util.Properties;
import javax.jms.Connection; import javax.jms.ConnectionFactory; import javax.jms.Destination; import javax.jms.MessageConsumer; import javax.jms.Session; import javax.jms.TextMessage; import javax.naming.Context; import javax.naming.InitialContext; import javax.naming.NamingException;
/** * 同步接收P2P消息 * * @author liuyan * */ public class JbossSyncMessageReciveriver {
/** * 消息消费者 */ public void reciveMessage() {
try { String Connection_Factory = "ConnectionFactory";
Context context = getInitialContext();
ConnectionFactory connectionFactory = (ConnectionFactory) context .lookup(Connection_Factory);
Destination dest = (Destination) context.lookup("jbossJMS");
Connection connection = connectionFactory.createConnection();
connection.start();
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
MessageConsumer reciver = session.createConsumer(dest);
TextMessage textMessage = (TextMessage) reciver.receive();
String messageText = textMessage.getText();
System.out.println("textMessage:" + textMessage);
System.out.println("消息内容" + messageText);
session.close(); connection.close(); } catch (Exception e) { e.printStackTrace(); }
}
/** * 获得应用服务上下文信息 * * @return */ private Context getInitialContext() { String init_factory = "org.jnp.interfaces.NamingContextFactory"; String serverURL = "jnp://127.0.0.1:1099"; Context context = null;
Properties properties = new Properties(); properties.put(Context.INITIAL_CONTEXT_FACTORY, init_factory); properties.put(Context.PROVIDER_URL, serverURL); try { context = new InitialContext(properties); } catch (NamingException e) { // TODO Auto-generated catch block e.printStackTrace(); } return context;
}
/** * @param args */ public static void main(String[] args) {
JbossSyncMessageReciveriver jbossSyncMessageReciveriver = new JbossSyncMessageReciveriver(); jbossSyncMessageReciveriver.reciveMessage(); }
} |
以上是一个同步接收消息的代码,流程是
1):获得应用上下文
2):根据上下文获得连接工厂,此处使用的是JBoss默认的连接工厂
3):从连接工厂里面获取JMS连接Connection
4):用Connection.start()方法,传输JMS消息
5):由JMS连接获得JMS消息回话Session
6):根据消息目的,由JMS会话创建消息消费者
7):同步接收消息,若没接受到消息,线程会阻塞
8):关闭JMS消息资源,session、connection