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 / queuebean属性并可用于创建实例(使用一个BeanFactory或者普通Java 代码code)。或者考虑从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 m = new HashMap();
  m.put("Name", "Mark");
  m.put("Age", new Integer(47));
  jmsTemplate.convertAndSend("testQueue", m, new MessagePostProcessor() {
    public Message postProcessMessage(Message message) throws JMSException {
      message.setIntProperty("AccountID", 1234);
      message.setJMSCorrelationID("123-00001");
      return message;
    }
  });
}

This results in a message of the form:

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

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()方法执行这些回调方法。