19.3. 发送消息

JmsTemplate 包含许多方便的方法来发送消息。有些发送方法可以使用 javax.jms.Destination 对象指定目的地,也可以使用字符串在JNDI中查找目的地。没有目的地参数的发送方法使用默认的目的地。这里有个例子使用1.0.2版的JMS实现发送消息到一个队列。

import javax.jms.ConnectionFactory;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.Queue;
import javax.jms.Session;

import org.springframework.jms.core.MessageCreator;
import org.springframework.jms.core.JmsTemplate;
import org.springframework.jms.core.JmsTemplate102;

public class JmsQueueSender {

    private JmsTemplate jmsTemplate;
    private Queue queue;

    public void setConnectionFactory(ConnectionFactory cf) {
        this.jmsTemplate = new JmsTemplate102(cf, false);
    }

    public void setQueue(Queue queue) {
        this.queue = queue;
    }

    public void simpleSend() {
        this.jmsTemplate.send(this.queue, new MessageCreator() {
            public Message createMessage(Session session) throws JMSException {
              return session.createTextMessage("hello queue world");
            }
        });
    }
}

这个例子使用 MessageCreator 回调接口从提供的 Session 对象中创建一个文本消息,并且通过一个 ConnectionFactory 的引用和指定消息域的布尔值来创建 JmsTemplate。提供了一个无参数的构造器和 connectionFactory / queue Bean属性并可用于创建实例(使用一个BeanFactory或者普通Java代码)。或者考虑从Spring的基类 JmsGatewaySupport,它对JMS配置具有内置的Bean属性,继承一个类。

当在应用上下文中配置JMS 1.0.2时,重要的是记得设定布尔属性 pubSubDomain 的值以指明你是要发送到队列还是主题。

方法 send(String destinationName, MessageCreator creator) 让你利用目的地的字符串名字发送消息。如果这个名字在JNDI中注册,你应当将模板中的 destinationResolver 属性设置为 JndiDestinationResolver 的一个实例。

如果你创建 JmsTemplate 并指定一个默认的目的地,send(MessageCreator c) 发送消息到这个目的地。

19.3.1. 使用消息转换器

为便于发送领域模型对象,JmsTemplate 有多种以一个Java对象为参数并做为消息数据内容的发送方法。JmsTemplate 里可重载的方法 convertAndSendreceiveAndConvert 将转换的过程委托给接口 MessageConverter 的一个实例。这个接口定义了一个简单的合约用来在Java对象和JMS消息间进行转换。缺省的实现 SimpleMessageConverter 支持 StringTextMessagebyte[]BytesMesssage,以及 java.util.MapMapMessage 之间的转换。使用转换器,可以使你和你的应用关注于通过JMS接收和发送的业务对象而不用操心它是具体如何表达成JMS消息的。

目前的沙箱模型包括一个 MapMessageConverter,它使用反射转换JavaBean和 MapMessage。其他流行可选的实现方式包括使用已存在的XML编组的包,例如JAXB、Castor、XMLBeans或XStream的转换器来创建一个表示对象的 TextMessage

为方便那些不能以通用方式封装在转换类里的消息属性,消息头和消息体的设置,通过 MessagePostProcessor 接口你可以在消息被转换后并且在发送前访问该消息。下例展示了如何在 java.util.Map 已经转换成一个消息后更改消息头和属性。

public void sendWithConversion() {
    Map map = new HashMap();
    map.put("Name", "Mark");
    map.put("Age", new Integer(47));
    jmsTemplate.convertAndSend("testQueue", map, new MessagePostProcessor() {
        public Message postProcessMessage(Message message) throws JMSException {
            message.setIntProperty("AccountID", 1234);
            message.setJMSCorrelationID("123-00001");
            return message;
        }
    });
}

这将产生一个如下的消息格式:

MapMessage={
    Header={
        ... standard headers ...
        CorrelationID={123-00001}
    }
    Properties={
        AccountID={Integer:1234}
    }
    Fields={
        Name={String:Mark}
        Age={Integer:47}
    } 
}

19.3.2. SessionCallbackProducerCallback

虽然send操作适用于许多常见的使用场景,但是有时你需要在一个JMS Session 或者 MessageProducer 上执行多个操作。接口 SessionCallbackProducerCallback 分别提供了JMS SessionSession / MessageProducer 对。JmsTemplate 上的 execute() 方法执行这些回调方法。