1.
我们还记得一般的JDBC是如何笨拙地处理连接、语句、结果集和异常的。不幸地是,JMS处理方式和它类似,有很多样本代码。很多JMS例子中的代码都是重复的。因此,与JdbcTemplate类似,Spring提供了JmsTemplate来处理样本代码。
2.
你可以使用JmsTemplate来创建连接,获取会话并进行收发消息。这样就可以只关注于发送消息的开发或是处理接收消息。另 外,JmsTemplate还可以细化JMSException的处理。JmsTemplate能够捕获该异常并不同的未检查(unchecked)子类 异常,如:DestinationResolutionExc
其实,JMSException提供了一组子类用于详尽地表明异常原因,但是他们都是checked类型的,所以也就必须被捕获,而JmsTemplate将会为你做这件事情。
绑定JmsTemplate
<</em>bean id="jmsTemplate"
</</em>bean>
因此JmsTemplate需要知道如何连接到message broker,所以我们需要设置connectionFactory属性,令其引用一个JMS的ConnectionFactory接口实现类,在这里是 connectionFactory。JmsTemplate还有一些其他属性,如果需要我们再介绍。
消息发送
对于RoadRantz例子来说,RoadRantz应用会给每个motorist发送一些有用的第三方信息,如果motorist对此感兴趣,他 的信息就将被加到一个单独的销售系统中。当首次注册时,如果用户选择接收第三方信息,那么他们的名字和邮件地址就以JMS消息的方式被发送到这个系统中。
而在RoadRantz端,我们希望使用JmsTemplate来发送motorist信息给Roadantz销售系统。下面的RantzMarketingGateImpl即实现了与销售系统的交互。
public class RantzMarketingGatewayImp
implements RantzMarketingGateway {
});
}
private JmsTemplate jmsTemplate;
public void setJmsTemplate(JmsTemplate jmsTemplate) {
}
private Destination destination;
public void setDestination(Destination destination) {
}
}
上面代码中的sendMotoristInfo方法最为关键。其实它只是调用JmsTemplate的send方法来发送消息。
<</em>bean id="marketingGateway"
</</em>bean>
值得注意的是,sendMotorist方法只关注于消息的创建和发送——JmsTemplate为我们处理其他的代码,而且我们不需要手工去编写 捕获JMSException的代码,JmsTemplate将会捕获被抛出的JMSException并将其以Spring的未检查异常重新抛出。
设置默认destination
<</em>bean id="jmsTemplate"
</</em>bean>
现在调用send方法就不用再指定了destination参数了,只需要一个MessageCreator即可。JmsTemplate会将消息 发送到默认的destination处,我们也不需要在RantzMarketingGateImpl的bean配置中指定destination了:
<</em>bean id="marketingGateway"
</</em>bean>
因为我们不再需要在RantzMarketingGateImpl中指定destination,所以destination属性和代码中的setter方法都可以去掉了。
接收消息
JmsTemplate可以负责发送消息,它可以接收消息吗?是的,它可以。实际上用JmsTemplate接收消息更简单。你只需调用JmsTemplate的receive方法。
public class MarketingReceiverGateway
}
catch (JMSException e) {
}
Return motorist;
}
private JmsTemplate jmsTemplate;
public void setJmsTemplate(JmsTemplate jmsTemplate) {
}
}
当调用receive方法时,JmsTemplate会再次帮我们处理那些诸如连接,会话之类的样本工作,然后再调用receive方法。 JmsTemplate的receive方法是同步的。默认情况下,调用receive方法之后将会等待消息发送至destination。不过你可以指 定一个接收超时receiveTimeout属性,例如:
<</em>bean id="jmsTemplate"
</</em>bean>
当然,你可以使用指定的destination,如:
MapMessage msg = (MapMessage) jmsTemplate.receive(destination);
另外,你还可以通过名字来指定一个destination,并让Spring的destination解析器自动地解析destination,如:
MapMessage msg =
(MapMessage) jmsTemplate.receive(“rantz.marketing.queue”);
同步接收消息并不是唯一的选择。Spring也提供了消息的异步接收方式。下面让我们看看如何让JmsTemplate自动实现XML消息和Java对象之间的转换。
3.
被发送的消息是由createMessage方法中的异步MessageCreator实例创建的,通过使用Motorist对象属性将其放入一个 MapMessage对象。同时在接收端,MarketingReceiverGateway
Spring提供了专门用于消息转换的接口:MessageConverter。
public interface MessageConverter {
}
MessageConverter接口很简单,只有两个方法。如果要发送消息,toMessage方法会将一个Java对象转换成消息。在接收端,fromMessage方法将消息转换成Java对象。我们需要在应用中实现该接口
收发转换过的消息
public void sendMotoristInfo(final Motorist motorist) {
}
JmsTemplate的convertAndSend方法会自动地调用toMessage方法用于发送消息。不适用默认destination的调用方式如下:
jmsTemplate.convertAndSend(destination, motorist);或
jmsTemplate.convertAndSend(“rantz.marketing.queue”, motorist);
在接收端,我们也不必调用fromMessage方法,相反,我们可以使用receiveAndConvert方法:
public SpammedMotorist receiveSpammedMotorist() {
}
同样你也可是传递一个destination参数来使用非默认的destination。现在还有一个问题需要搞清楚,JmsTemplate的 convertAndSend和receiveAndConvert方法使用消息转化器来进行消息转换,那么JmsTemplate是怎么知道这个消息转 换器呢?
指定消息转换器
<</em>bean id="motoristConverter"
然后,在JmsTemplate的配置中你需要将此converter指定到messageConverter属性上,如:
<</em>bean id="jmsTemplate"
</</em>bean>
4.
你可能还记得,因为有了JdbcDaoSupport这个用于编写基于JDBC的DAO的类,Spring可以更加方便地使用JdbcTemplate。同样地,Spring提供了JmsGatewaySupport类,它是提供JMS通路支持的基类。
目前为止我们创建了jmsTemplate和destination属性。尽管现在的代码量不多,但是如果应用中存在多个JMS通路,那必将导致大 量重复的代码。为了解决这个问题,我们需要令RantzMarketingGateImpl类继承JmsGatewaySupport类,例如:
public class RantzMarketingGatewayImp
throws JMSException {
MapMessage msg = session.createMapMessage();
msg.setString(“lastName”, motorist.getLastName());
msg.setString(“firstName”, motorist.getFirstName());
msg.setString(“email”, motorist.getEmail());
return msg;
}
}
注意jmsTemplate属性和setJmsTemplate方法不见了。这个版本的RantzMarketingGateImpl会调用getJmsTemplate来获取JmsTemplate对象。所以,jmsTemplate和它的setter方法就不需要了。
<</em>bean id="marketingGateway"
</</em>bean>
这样配置的话,JmsGatewaySupport将自动根据指定的连接工厂来创建JmsTemplate对象。在Spring中不需额外声明JmsTemplate。不过这种方法也有不足之处:
·你只能为一个JmsTemplate指定一个默认destination。如果JmsGatewaySupport创建了自己的 JmsTemplate,你就不能再指定默认destination了。你就只能显式地调用带有destination参数的send或receive方 法。
·你只能为一个JmsTemplate编写一个消息转换器。如果JmsGatewaySupport创建了JmsTemplate,你就不能使用消息转换器了。你也必须显式地处理消息转换