JMS API
JMS源于企业应用对于消息中间件的需求,使应用程序可以通过消息进行异步处理而互不影响。JMS应用程序有四个组成部分:JMS服务提供者、消息管理对象、消息的生产者消费者和消息本身。
l JMS服务提供者实现消息队列和通知,同时实现消息管理的API。JMS已经是J2EE API的一部分,J2EE服务器都提供JMS服务。
l 消息管理对象提供对消息进行操作的API。JMS API中有两个消息管理对象:ConnectionFactory和Destination,根据消息的消费方式的不同ConnectionFactory可以分为QueueConnectionFactory和TopicConnectionFactory,Destination可以分为Queue和Topic。用这两个管理对象可以建立到消息服务的会话。
l 消息的生产者和消费者。它们可以毫不相干,只需要消息的消费者知道如何使用消息即可。根据消息消费者数目的不同,消息的消费者分为两类:subscriber 和receiver,同样消息发送者也分为两类:Publisher和Sender。
l 消息。JMS API规定了五种消息:Message、MapMessage、TextMessage、ByteMessage、StreamMessage和ObjectMessage
消费形式的不同造成JMS有两组平行的API,这就是JMS的PTP(point to point)模型和PUB/SUB(publisher和subscriber、出版和订阅)模型。PTP的消息应用中一个消息只有一个消费者,消费后该消息即不再有效。而PUB/SUB应用中一个消息可以有多个订阅者,而且每个订阅者不一定非要处理该消息。
下面是JMS应用的基本模型:
开发工具是JBuilder和WebLogic。
1. 发送和接收消息。需要使用JMS API手动编码实现发送和接收消息的有三个地方:发送消息的Servlet、接收消息的Servlet和发送计算完成消息的MessageDrivenBean。对于发送和接收消息都需要的QueueConnectionFactory、QueueConnection、Queue和QueueSession等对象则利用Servlet和MDB的生命周期方法获得和释放,在Servlet的init方法和MDB的ejbCreate方法中获得资源并创建需要的对象,在Servlet的destroy和MDB的ejbRemove方法中释放资源。
获得资源:
public void init() throws ServletException {
try{
InputStream in = this.getClass().getClass().getClassLoader().
getResourceAsStream("jndi.properties");
Properties p = new Properties();
p.load(in);
ctx = new InitialContext(p);
}catch(Exception ex){
ex.printStackTrace();
}
try{
connectionFactory = (QueueConnectionFactory) ctx.lookup(
connectionFactoryName);
queue = (Queue) ctx.lookup(queueName);
connection = (javax.jms.QueueConnection) ( (QueueConnectionFactory)
connectionFactory).
createQueueConnection();
queueSession = ( (javax.jms.QueueConnection) connection).
createQueueSession(false, Session.AUTO_ACKNOWLEDGE);
queueSender = queueSession.createSender(queue);
}catch(Exception ex){
ex.printStackTrace();
}
}
发送消息:
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String taskid = request.getParameter("taskid");
try{
String completedmsg = "任务" taskid "执行完成";
ObjectMessage om = queueSession.createObjectMessage(new CalculateCompleted(userid, taskid, completedmsg));
queueSender.send(om);
}catch(Exception ex){
ex.printStackTrace();
}
}
接收消息。这里对消息在Servlet中作了转存,messages是一个Hashtable对象。
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
boolean rflag = true;
try {
messageConsumer = (QueueReceiver) queueSession.createReceiver(queue);
connection.start();
while (rflag) {
Message m = messageConsumer.receiveNoWait();
if (m != null) {
if (m instanceof ObjectMessage) {
ObjectMessage message = (ObjectMessage) m;
MessageBody mb = (MessageBody)message.getObject();
ArrayList a = (ArrayList)messages.get(mb.getUserID());
if(a == null){
a = new ArrayList();
a.add(mb);
messages.put(mb.getUserID(), a);
}else{
a.add(mb);
}
}
else {
rflag = false;
}
}
else {
rflag = false;
}
}
connection.stop();
}
catch (JMSException e) {
e.printStackTrace();
}
}
释放资源:
public void destroy() {
try{
if(connection != null)connection.close();
}catch(Exception ex){
ex.printStackTrace();
}
}
MDB的jebCreate方法和上面init方法的内容一样,ejbRemove和上面destroy方法的内容相同。MDB的计算过程实现在onMessage()方法中,计算完成后发送一条消息,发送消息的过程上面已有,不再赘述。
2. WebLogic的JMS服务配置。这里使用最简单的JMS配置,除了名字和JNDI名其余的均使用缺省值。
a) 启动WebLogic,打开web console
b) 展开左侧的JMS节点,新建一个JMS Server。名字随意。
c) 为刚建立的JMS Server建立两个Queue。JNDI名分别为::jms/calculate和jms/completed。
d) 建立一个ConnectionFacotry。JNDI名:jms/conn_factory
3. 配置MDB。这里除了要指定MDB监听的Queue外,因为MDB需要向另外的Queue发送计算成功的消息,还需要把上面WebLogic中配置的jms/conn_factory作为资源添加到MDB的resource-ref中,把jms/completed作为环境资源添加到MDB的resource-env-resource中。
4. 部署执行。用JBuilder建立一个EAR然后部署,非常简单。如果各位想要测试只需要建立一个简单的客户端应用程序,然后将MDB的onMessage方法简单实现为消息转发就可以了。
JMS是一组很强大的API,不仅可以在一个应用程序中实现异步通信,也常被用来在不同的应用程序间传递数据,同时JMS也支持分布式事务,达到了企业应用的要求