SpringJMS解析2-JmsTemplate
尽管消息接收可以使用消息监听器的方式替代模版方法,但是在发送的时候是无法替代的,在Spring中必须要使用JmsTemplate提供的方法来进行发送操作,可见JmsTemplate类的重要性,那么我们对于Spring整合消息服务的分析就从JmsTemplate开始。
查看JmsTemplate的类型层级结构图发现实现了InitializingBean接口,接口方法实现是在JmsAccessor类中。发现函数中只是一个验证的功能,并没有逻辑实现。
public void afterPropertiesSet() {
if (getConnectionFactory() == null) {
throw new IllegalArgumentException("Property 'connectionFactory' is required");
}
}
在Spring中发送消息可以通过JmsTemplate中提供的方法来实现。
public void send(final String destinationName, final MessageCreator messageCreator) throws JmsException {
execute(new SessionCallback<Object>() {
@Override
public Object doInJms(Session session) throws JMSException {
Destination destination = resolveDestinationName(session, destinationName);
doSend(session, destination, messageCreator);
return null;
}
}, false);
}
现在的风格不得不让我们回想起JdbcTemplate的类实现风格,极为相似,都是提取一个公共的方法作为最底层、最通用的功能实现,然后又通过回调函数的不同来区分个性化的功能。我们首先查看通用代码的抽取实现。
通用代码抽取execute()
在execute中封装了Connection以及Session的创建操作
public <T> T execute(SessionCallback<T> action, boolean startConnection) throws JmsException {
Assert.notNull(action, "Callback object must not be null");
Connection conToClose = null;
Session sessionToClose = null;
try {
//事务相关
Session sessionToUse = ConnectionFactoryUtils.doGetTransactionalSession(
getConnectionFactory(), this.transactionalResourceFactory, startConnection);
if (sessionToUse == null) {
//创建connection
conToClose = createConnection();
//根据connection创建session
sessionToClose = createSession(conToClose);
//是否开启向服务器推送连接信息,只有接收信息时需要,发送时不需要
if (startConnection) {
conToClose.start();
}
sessionToUse = sessionToClose;
}
if (logger.isDebugEnabled()) {
logger.debug("Executing callback on JMS Session: " + sessionToUse);
}
//调用回调函数
return action.doInJms(sessionToUse);
}
catch (JMSException ex) {
throw convertJmsAccessException(ex);
}
finally {
//关闭session
JmsUtils.closeSession(sessionToClose);
//释放连接
ConnectionFactoryUtils.releaseConnection(conToClose, getConnectionFactory(), startConnection);
}
}
为了发送一条消息需要做很多工作,需要很多的辅助代码,而这些代码又都是千篇一律的,没有任何的差异,所以execute方法的目的就是帮助我们抽离这些冗余代码使我们更加专注于业务逻辑的实现。从函数中看,这些冗余代码包括创建Connection、创建Session、当然也包括关闭Session和关闭Connection。而在准备工作结束后,调用回调函数将程序引入用户自定义实现的个性化处理。
发送消息的实现
有了基类辅助实现,使Spring更加专注于个性的处理,也就是说Spring使用execute方法中封装了冗余代码,而将个性化的代码实现放在了回调函数doInJms函数中。在发送消息的功能中回调函数通过局部类实现。
protected void doSend(Session session, Destination destination, MessageCreator messageCreator)
throws JMSException {
Assert.notNull(messageCreator, "MessageCreator must not be null");
MessageProducer producer = createProducer(session, destination);
try {
Message message = messageCreator.createMessage(session);
if (logger.isDebugEnabled()) {
logger.debug("Sending created message: " + message);
}
doSend(producer, message);
// Check commit - avoid commit call within a JTA transaction.
if (session.getTransacted() && isSessionLocallyTransacted(session)) {
// Transacted session created by this template -> commit.
JmsUtils.commitIfNecessary(session);
}
}
finally {
JmsUtils.closeMessageProducer(producer);
}
}
在发送消息遵循着消息发送的规则,比如根据Destination创建MessageProducer、创建Message,并使用MessageProducer实例来发送消息。
接收消息
我们通常使用jmsTemplate.receive(destination)来接收简单的消息,那么这个功能Spring是如何封装的呢?
@Override
public Message receive(Destination destination) throws JmsException {
return receiveSelected(destination, null);
}
@Override
public Message receiveSelected(final Destination destination, final String messageSelector) throws JmsException {
return execute(new SessionCallback<Message>() {
@Override
public Message doInJms(Session session) throws JMSException {
return doReceive(session, destination, messageSelector);
}
}, true);
}
protected Message doReceive(Session session, Destination destination, String messageSelector)
throws JMSException {
return doReceive(session, createConsumer(session, destination, messageSelector));
}
protected Message doReceive(Session session, MessageConsumer consumer) throws JMSException {
try {
// Use transaction timeout (if available).
long timeout = getReceiveTimeout();
JmsResourceHolder resourceHolder =
(JmsResourceHolder) TransactionSynchronizationManager.getResource(getConnectionFactory());
if (resourceHolder != null && resourceHolder.hasTimeout()) {
timeout = Math.min(timeout, resourceHolder.getTimeToLiveInMillis());
}
Message message = doReceive(consumer, timeout);
if (session.getTransacted()) {
// Commit necessary - but avoid commit call within a JTA transaction.
if (isSessionLocallyTransacted(session)) {
// Transacted session created by this template -> commit.
JmsUtils.commitIfNecessary(session);
}
}
else if (isClientAcknowledge(session)) {
// Manually acknowledge message, if any.
if (message != null) {
message.acknowledge();
}
}
return message;
}
finally {
JmsUtils.closeMessageConsumer(consumer);
}
}
实现的套路与发送差不多,同样还是使用execute函数来封装冗余的公共操作,而最终的目标还是通过consumer.receive()来接收消息,其中的过程就是对于MessageConsumer的创建以及一些辅助操作。
SpringJMS解析2-JmsTemplate的更多相关文章
- SpringJMS解析-JmsTemplate
目录 通用代码抽取execute() 发送消息的实现 接收消息 尽管消息接收可以使用消息监听器的方式替代模版方法,但是在发送的时候是无法替代的,在Spring中必须要使用JmsTemplate提供的方 ...
- SpringJMS解析1-使用示例
Spring配置文件: <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="h ...
- SpringJMS解析--使用示例
Spring配置文件: <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="h ...
- SpringJMS解析3-监听器
消息监听器容器是一个用于查看JMS目标等待消息到达的特殊bean,一旦消息到达它就可以获取到消息,并通过调用onMessage()方法将消息传递给一个MessageListener实现.Spring中 ...
- SpringJMS解析--监听器
消息监听器容器是一个用于查看JMS目标等待消息到达的特殊bean,一旦消息到达它就可以获取到消息,并通过调用onMessage()方法将消息传递给一个MessageListener实现.Spring中 ...
- Spring JMS 官方文档学习
最后部分的XML懒得写了,因为个人更倾向于JavaConfig形式. 为知笔记版本见这里,带格式~ 做了一个小demo,放到码云上了,有兴趣的点我. 说明:需要先了解下JMS的基础知识. 1.介绍 S ...
- spring-jms,spring-boot-starter-activemq JmsTemplate 发送方式
spring-jms,spring-boot-starter-activemq JmsTemplate 发送方式 背景: 原来我准备是setDefaultDestinationName 设置队列的名称 ...
- AMQ学习笔记 - 13. Spring-jms的配置
概述 如何使用spring-jms来简化jms客户端的开发? 这篇文章主要记录如何配置以便以后复用,而非原理的讲解,有些内容我 没有掌握原理. producer端 producer端负责发送,这里使用 ...
- Spring框架之jms源码完全解析
Spring框架之jms源码完全解析 我们在前两篇文章中介绍了Spring两大核心IOC(Inversion of Control控制反转)和AOP(Aspect Oriented Programmi ...
随机推荐
- vps mysql自动关闭
买了个阿里云的vps 装了一个wordpress,mysql一直自动关闭,百思不得其解,只有搜索 最后才发现是因为服务器内存太小,毕竟是最便宜的才512m ---------------------- ...
- Effective C++ -----条款49:了解new-handler 的行为
set_new_handler允许客户指定一个函数,在内存分配无法获得满足时被调用. Nothorw new 是一个颇为局限的工具,因为它只适用于内存分配:后继的构造函数调用还是可能抛出异常.
- 监控Tomcat解决方案(监控应用服务器系列文章分享)
使用JMX接口开发监控程序 ◆ 全部代码需要从零开始,代码量较大 ◆ 支持各不同版本比较麻烦,每个版本可能有差异 ◆ 可支配性强 ◆ 最重要的一个缺点是,配置比较麻烦 Tomcat激活JMX远 ...
- android学习————项目导入常见错误整理(转载)
详细请访问http://4789781.blog.51cto.com/4779781/1031107
- 20145213《Java程序设计》第四周学习总结
20145213<Java程序设计>第四周学习总结 教材学习内容总结 本周任务是学习面向对象的继承.接口以及之后的如何活用多态.(还真是路漫漫其修远兮啊!)教材也是延续上周艰深晦涩的语言风 ...
- 浅析_tmain()与main()的区别
转自http://www.jb51.net/article/34516.htm _tmain()是为了支持unicode所使用的main一个别名,既然是别名,应该有宏定义过的,在哪里定义的呢?就在那个 ...
- AFNetworking(AFN)总结
AFNetworking(AFN) ----主要做下载上传之用 //他是干啥的?发送请求,主要做下载上传之用 (苹果自带有获取服务器数据的方法NSURLConnection send,AFNetwor ...
- HTTP协议/RTSP协议/RTMP协议的区别
RTSP. RTMP.HTTP的共同点.区别 共同点: 1:RTSP RTMP HTTP都是在应用应用层. 2: 理论上RTSP RTMPHTTP都可以做直播和点播,但一般做直播用RTSP RTMP, ...
- android HTTPclient
Apache包是对android联网访问封装的很好的一个包,也是android访问网络最常用的类. 下面分别讲一下怎么用HttpClient实现get,post请求. 1.Get 请求 1 2 3 4 ...
- Deci and Centi Seconds parsing in java
http://stackoverflow.com/questions/14558663/deci-and-centi-seconds-parsing-in-java