2.5使用JMS API创建JMS应用
因不同的商业要求,创建一个JMS应用可以很简单也可以很复杂。就像JDBC,JNDI,EJBs等API,抽象JMS API,使得JMS代码和商业逻辑相分离是必须的。这个概念不会在这里讨论,因为这要涉及到模式和应用架构,不是一两句话可以说完的。下面是一些简单的例子,它们向你展示了一个最基本的JMS APIs的使用,
2.5.1 一个简单的JMS应用
一个JMS应用使用Java语言编写的,它组合了各个部分来和JMS一起工作。这些部分在2.3节已经讨论过。一个简单的JMS应用会下面的步骤:
- 请求一个JMS连接工i厂。
- 是用连接工厂创建连接。
- 启动JMS连接。
- 通过连接创建session。
- 获取一个目标。
- 创建一个生产者,或a.创建一个生产者,b.创建一条JMS消息并发送到目标
- 创建一个消费者,或a.创建一个消费者,b.注册一个消息监听器。
- 发送或接受消息。
- 关闭所有资源(连接,会话,生产者,消费者等)。
这些步骤是用来展示使用JMS的一个简单流程。下面的列表用来展现创建一个生产者并发送消息的代码。
Listing 2.8 Sending a JMS message
public class MyMessageProducer {
...
ConnectionFactory connectionFactory;
Connection connection;
Session session;
Destination destination;
MessageProducer producer;
Message message;
boolean useTransaction = false;
try {
Context ctx = new InitialContext();
connectionFactory =
(ConnectionFactory) ctx.lookup("ConnectionFactoryName");
connection = connectionFactory.createConnection();
connection.start();
session = connection.createSession(useTransaction,
Session.AUTO_ACKNOWLEDGE);
destination = session.createQueue("TEST.QUEUE");
producer = session.createProducer(destination);
message = session.createTextMessage("this is a test");
producer.send(message);
} catch (JMSException jmsEx) {
...
} finally {
producer.close();
session.close();
connection.close();
}
}
列表2.8,首先创建了一个上下文。通常情况下,上下文是通过JNDI路径获取的,这个例子只是用来演示的。在初始化的上下文中通过使用连接工厂的唯一名字获取它。通过连接工厂,JMS连接被创建和启动。这之后,JMS客户端可以开始和代理器交互了。通过JMS连接,JMS会话被创建并且使用自动答复消息类型。JMS队列通过会话被创建。接下来是使用会话和目标创建生产者。之后通过会话创建了一条简单的文本消息并由生产者发送出去。最后的一个步骤是关闭所有用到的对象。
2.8的例子演示了一个最简单的创建生产者和发送一条消息到目标的动作。注意,有没有一个消费者在等待这样一条消息对于生产者是不重要的。MOMs作用就是生产者和消费者的一个中间调节,这对于创建JMS应用非常有帮助。开发者并不需要考虑如何获取这样的中间调节功能,JMS APIs已经提供了。下面的例子则是演示一个创建消费者和接收消息的动作。
Listing 2.9 Receiving a JMS message synchronously
public class MySyncMessageConsumer {
...
ConnectionFactory connectionFactory;
Connection connection;
Session session;
Destination destination;
MessageConsumer consumer;
Message message;
boolean useTransaction = false;
try {
Context ctx = new InitialContext();
connectionFactory =
(ConnectionFactory) ctx.lookup("ConnectionFactoryName");
connection = connectionFactory.createConnection();
connection.start();
session = connection.createSession(useTransaction,
Session.AUTO_ACKNOWLEDGE);
destination = session.createQueue("TEST.QUEUE");
consumer = session.createConsumer(destination);
message = (TextMessage) consumer.receive(1000);
System.out.println("Received message: " + message);
} catch (JMSException jmsEx) {
...
} finally {
producer.close();
session.close();
connection.close();
}
}
2.9的例子和2.8很像,因为它们都需要相同的步骤直到消费者被创建。之后,消费者被用来从目标接受消息。最后一部分代码是关闭所有的对象。同样地,这并不要求现在有一个生产者在发送消息。所有的中间和临时存储都是JMS提供者做的。2.9演示的是同步的消息接收。这意味着JMS消费者发送一个请求到JMS提供者,并等待响应。消费者必须通过循环一次次地获取消息。JMS消费者并非只能通过同步方法获取消息。
JMS API同样提供了异步获取消息的方法。JMS提供者会将消息推送到消费者。下面是一个异步消息消费的例子。
Listing 2.10 Receiving a JMS message asynchronously
public class MyAsyncMessageConsumer implements MessageListener {
...
ConnectionFactory connectionFactory;
Connection connection;
Session session;
Destination destination;
MessageProducer producer;
Message message;
boolean useTransaction = false;
try {
Context ctx = new InitialContext();
connectionFactory =
(ConnectionFactory) ctx.lookup("ConnectionFactoryName");
connection = connectionFactory.createConnection();
connection.start();
session = connection.createSession(useTransaction,
Session.AUTO_ACKNOWLEDGE);
destination = session.createQueue("TEST.QUEUE");
consumer = session.createConsumer(destination);
consumer.setMessageListener(this);
} catch (JMSException jmsEx) {
...
} finally {
producer.close();
session.close();
connection.close();
}
public void onMessage(Message message) {
if (message instanceof TextMessage) {
System.out.println("Received message: " + message);
}
}
}
2.10的不同之处在于它实现了MessageListener接口的onMessage方法并且将实现类注册到JMS提供者。异步消息接收是很有用的。这意味着消费者不再需要人工地不停地从提供者那里拉消息。而是,通过注册到提供者的MessageListener实现作为回调,onMessage方法将在消息被投递的时候自动调用。
JMS多线程应用
JMS定义了很多并发的对象,但是只有一部分支持并发访问。ConnectionFactory,Connection,Destination对象支持并发访问;Session,MessageProducer,MessageConsumer对象不支持并发访问。也就是说,Session,MessageProducer,MessageConsumer对象不应该在多线程中共享
对于JMS API消息消费还有一点要说明。它提供异步的消息消费,这和EJB的消息驱动bean(message-driven beans)一样。