JMS生产者+单线程发送-我们到底能走多远系列(29)
我们到底能走多远系列(29)
扯淡:
“然后我俩各自一端/望着大河弯弯/终于敢放胆/嘻皮笑脸/面对/人生的难” --- 《山丘》
“迎着风/迎向远方的天空/路上也有艰难/也有那解脱/都走得从容” --- 《与你到永久》
“遇上冷风雨休太认真/自信满心里休理会讽刺与质问/笑骂由人洒脱地做人/少年人洒脱地做人/继续行洒脱地做人” ---《沉默是金》
主题:
使用JMS将共通模块分离出去,比如发短信模块,可以在远程的机器上跑customer,然后各个应用使用发短信功能是只要向远程机器发送msg即可。
类似于下图:

对于图中的Producer的实现都差不多,主要是选择什么样的Jms第三方实现。对于Customer我们不必关心.
比如下面的代码是HornetQ的Producer的样例代码:
public class JmsProducer implements ExceptionListener,FailureListener{
private final Logger logger = LoggerFactory.getLogger(JmsProducer.class);
private String queueName;
private String jmsHost;
private int jmsPort;
private ConnectionFactory cf;
private Queue queue;
private Connection queueConnection;
private Session queueSession;
private MessageProducer queueProducer;
public void init() throws Exception {
queue = HornetQJMSClient.createQueue(queueName);
Map<String, Object> connectionParams = new HashMap<String, Object>();
connectionParams.put(TransportConstants.PORT_PROP_NAME, jmsPort);
connectionParams.put(TransportConstants.HOST_PROP_NAME, jmsHost);
TransportConfiguration transportConfiguration = new TransportConfiguration(NettyConnectorFactory.class.getName(),
connectionParams);
HornetQConnectionFactory hornetQConnectionFactory = HornetQJMSClient.createConnectionFactoryWithoutHA(JMSFactoryType.CF, transportConfiguration);
hornetQConnectionFactory.setClientFailureCheckPeriod(60000);
hornetQConnectionFactory.setRetryInterval(2000); // 2 seconds for first retry
hornetQConnectionFactory.setRetryIntervalMultiplier(1.5); // 1.5 times loner betrween retrys
hornetQConnectionFactory.setMaxRetryInterval(20000); // Wait max 20 secs between retrys
hornetQConnectionFactory.setReconnectAttempts(-1); // Retry forever
hornetQConnectionFactory.setConnectionTTL(60000); //The default value for connection ttl is 60000ms
hornetQConnectionFactory.setClientFailureCheckPeriod(30000);//The default value for client failure check period is 30000ms
cf = (ConnectionFactory)hornetQConnectionFactory;
queueConnection = cf.createConnection();
queueSession = queueConnection.createSession(false, Session.AUTO_ACKNOWLEDGE);
queueProducer = queueSession.createProducer(queue);
queueProducer.setTimeToLive(6000000);//100分钟失效
queueProducer.setDisableMessageID(true);//关闭消息id
queueProducer.setDisableMessageTimestamp(true);//关闭消息的时间戳
logger.info("init JmsProducer of "+queueName);
//queueConnection.start();
}
public void reConnect(){
logger.info(queueName+" reConnect");
}
public void destroy() throws Exception {
logger.info("destroy JmsProducer of "+queueName);
if(queueSession != null){
queueSession.close();
queueSession = null;
}
if(queueConnection != null){
queueConnection.close();
queueConnection = null;
}
}
public String getQueueName() {
return queueName;
}
public void setQueueName(String queueName) {
this.queueName = queueName;
}
public String getJmsHost() {
return jmsHost;
}
public void setJmsHost(String jmsHost) {
this.jmsHost = jmsHost;
}
public int getJmsPort() {
return jmsPort;
}
public void setJmsPort(int jmsPort) {
this.jmsPort = jmsPort;
}
public Session getQueueSession() {
return queueSession;
}
public void sendTextMessage(final TextMessage textMessage) throws JMSException {
try {
queueProducer.send(textMessage);
} catch (Exception e) {
// TODO: handle exception
logger.error("on sendTextMessage Exception="+e.getMessage());
}
}
public void onException(JMSException jmsex) {
// TODO Auto-generated method stub
logger.warn("on JmsProducer Exception="+jmsex.getMessage());
}
public void connectionFailed(HornetQException hqex, boolean arg1) {
// TODO Auto-generated method stub
logger.error("on JmsProducer connectionFailed,arg1="+arg1+",Exception="+hqex.getMessage());
}
}
一般性的,我们利用Spring 把这个JmsProducer 注入进自己的业务类里去使用即可:
spring的bean配置:
<bean id="jmsCodeProducer" class="com.sz.lvban.biz.bo.util.JmsProducer" init-method="init">
<property name="jmsHost" value="${jms.send.code.host}" />
<property name="jmsPort" value="${jms.send.code.port}" />
<property name="queueName" value="${jms.send.code.queueName}" />
</bean>
@Autowired
private JmsProducer jmsCodeProducer;
某方法直接调用:
textMsg = jmsCodeProducer.getQueueSession().createTextMessage();
textMsg.setText(smsJson.toJSONString());
jmsCodeProducer.sendTextMessage(textMsg);
这样就实现了让服务器上的customer干活的工作了。
然后,我们发现spring默认注入jmsCodeProducer使用了单例的模式,这样一来我们就可能考虑多线程调用冲突的问题。然而我们不能避免jmsCodeProducer的单例,毕竟init-method="init" 的init方法有点消耗的。
所以就搞了下面的方案:(上图的题部分)

使用一个queue做中间站,只要保证单线程从queue中取数据,就能实现一条条向远程服务器发送jms消息。
下面是一个实现的例子:
我们先配置一个ApnsMsgSender,有他来控制queue的行为,包括插入,取出数据,以及发送jms消息。
<bean id="ApnsMsgSender" class="com.sz.wxassistant.biz.bo.util.ApnsMsgSender" init-method="sendMsg">
<property name="jmsApnsProducer" ref="jmsApnsProducer"></property>
</bean>
注意init-method="sendMsg" 启动时,我们就需要启动一个线程来监控queue。
结合下代码:在这里我们使用了LinkedBlockingQueue,关于ArrayBlockingQueue和LinkedBlockingQueue之间的取舍,我没有实际测试过。
public class ApnsMsgSender {
// private ArrayBlockingQueue<TextMessage> queue = new
// ArrayBlockingQueue<TextMessage>(1024);
private LinkedBlockingQueue<TextMessage> jmsQueue = new LinkedBlockingQueue<TextMessage>();
private JmsProducer jmsApnsProducer;
private ExecutorService pool;
private Logger log = LoggerFactory.getLogger("ApnsMsgSender");
/**
* 启动入口
*/
public void sendMsg() {
pool = Executors.newCachedThreadPool(new MyThreadFactory());
pool.submit(new JmsSender());
}
public boolean addJms(TextMessage msg) {
return jmsQueue.offer(msg);
}
public TextMessage getMsg() {
TextMessage msg = null;
try {
// 取msg 10秒超时设置
msg = jmsQueue.poll(10, TimeUnit.SECONDS);
} catch (InterruptedException interuptedE) {
log.warn("poll jms error" + interuptedE);
} catch (Exception e) {
log.error("poll jms get unknown error: ", e);
}
return msg;
}
public JmsProducer getJmsApnsProducer() {
return jmsApnsProducer;
}
public void setJmsApnsProducer(JmsProducer jmsApnsProducer) {
this.jmsApnsProducer = jmsApnsProducer;
}
public TextMessage genTextMessage() throws JMSException {
return jmsApnsProducer.getQueueSession().createTextMessage();
}
private class JmsSender implements Runnable {
public void run() {
while (true) {
try {
// 从queue中取msg
TextMessage msg = getMsg();
if (msg != null && msg instanceof TextMessage) {
// 发送
jmsApnsProducer.sendTextMessage(msg);
}
} catch (JMSException jmsE) {
log.error("send jms error: " + jmsE);
} catch (Exception e) {
log.error("get unknown error: ", e);
}
}
}
}
class MyThreadFactory implements ThreadFactory {
public Thread newThread(Runnable r) {
Thread thread = new Thread(r);
// 线程设置为后台进程
thread.setDaemon(true);
thread.setName("ApnsMsgSender");
return thread;
}
}
}
解释:
我们的这个线程做了什么?
1, getMsg()
2, sendTextMessage(msg)
很明了的实现....
注:代码中还使用了ThreadFactory 来封装了一下线程。
外界代码调用怎么搞?
1,addJms 就可以了
只负责向queue里放,这样再多的线程都没有关系了。
TextMessage msg = apnsMsgSender.genTextMessage();
msg.setText("I love los angeles !");
apnsMsgSender.addJms(msg);
ok。到这里就实现了单线程发送jms消息的功能。
让我们继续前行
----------------------------------------------------------------------
努力不一定成功,但不努力肯定不会成功。
共勉。
JMS生产者+单线程发送-我们到底能走多远系列(29)的更多相关文章
- 服务调用方案(Spring Http Invoker) - 我们到底能走多远系列(40)
我们到底能走多远系列(40) 扯淡: 判断是否加可以效力于这家公司,一个很好的判断是,接触下这公司工作几年的员工,了解下生活工作状态,这就是你几年后的状态,如果满意就可以考虑加入了. 主题: 场景: ...
- ArrayBlockingQueue-我们到底能走多远系列(42)
我们到底能走多远系列(42) 扯淡: 乘着有空,读些juc的源码学习下.后续把juc大致走一边,反正以后肯定要再来. 主题: BlockingQueue 是什么 A java.util.Queue t ...
- ThreadPoolExecutor机制探索-我们到底能走多远系列(41)
我们到底能走多远系列(41) 扯淡: 这一年过的不匆忙,也颇多感受,成长的路上难免弯路,这个世界上没人关心你有没有变强,只有自己时刻提醒自己,不要忘记最初出发的原因. 其实这个世界上比我们聪明的人无数 ...
- Spring mvc源码url路由-我们到底能走多远系列(38)
我们到底能走多远系列38 扯淡: 马航的事,挺震惊的.还是多多珍惜身边的人吧. 主题: Spring mvc 作为表现层的框架,整个流程是比较好理解的,毕竟我们做web开发的,最早也经常接触的就是一个 ...
- node实现http上传文件进度条 -我们到底能走多远系列(37)
我们到底能走多远系列(37) 扯淡: 又到了一年一度的跳槽季,相信你一定准备好了,每每跳槽,总有好多的路让你选,我们的未来也正是这一个个选择机会组合起来的结果,所以尽可能的找出自己想要的是什么再做决定 ...
- node模拟http服务器session机制-我们到底能走多远系列(36)
我们到底能走多远系列(36) 扯淡: 年关将至,总是会在一些时间节点上才感觉时光飞逝,在平时浑浑噩噩的岁月里都浪费掉了太多的宝贵.请珍惜! 主题: 我们在编写http请求处理和响应的代码的时 ...
- js中this和回调方法循环-我们到底能走多远系列(35)
我们到底能走多远系列(35) 扯淡: 13年最后一个月了,你们在13年初的计划实现了吗?还来得及吗? 请加油~ 主题: 最近一直在写js,遇到了几个问题,可能初入门的时候都会遇到吧,总结下. 例子: ...
- html5实现饼图和线图-我们到底能走多远系列(34)
我们到底能走多远系列(34) 扯淡: 送给各位一段话: 人生是一个不断做加法的过程 从赤条条无牵无挂的来 到学会荣辱羞耻 礼仪规范 再到赚取世间的名声 财富 地位 ...
- Bean实例化(Spring源码阅读)-我们到底能走多远系列(33)
我们到底能走多远系列(33) 扯淡: 各位: 命运就算颠沛流离 命运就算曲折离奇 命运就算恐吓着你做人没趣味 别流泪 心酸 更不应舍弃 ... 主题: Spring源码阅读还在继 ...
随机推荐
- 亿级Web系统搭建——单机到分布式集群[转]
当一个Web系统从日访问量10万逐步增长到1000万,甚至超过1亿的过程中,Web系统承受的压力会越来越大,在这个过程中,我们会遇到很多的问题.为了解决这些性能压力带来问题,我们需要在Web系统架构层 ...
- Scala 入门——Eclipse开发环境搭建
Come From: http://lidrema.blog.163.com/blog/static/209702148201461145859142/ Scala: 一种类似java的编程.集成了面 ...
- IoTimerInLineHook
#ifndef CXX_IOTIMERINLINEHOOK_H # include "IoTimerInlineHook.h" #endif ULONG32 SSDT_NtOpen ...
- Android 主页面顶部栏的通知Notification ,可以自定义通知消息栏的风格,并且点击通知栏进人本程序。
常用的程序通知,显示到主页面的顶部栏. package com.lixu.tongzhi; import android.app.Activity; import android.app.Notifi ...
- C#.NET SQL数据库备份与还原解决方案
C#.NET SQL数据库备份与还原解决方案http://www.csframework.com/archive/1/arc-1-20110924-1841.htm 开发框架V2.2(快速开发版)系统 ...
- 用Navicat for MYsql创建表,插入中文显乱码
段都有编码设置.出现乱码肯定是你现在用的编码混乱造成的 解决办法: 第一步 先改数据库编码 先修改你的数据库,如果你页面用的是UTF-8编码那么你数据库内的编码也需要设置为UTF-8,每个字段都需要设 ...
- 滑雪(dp好题)
题目描述:贝西去科罗拉多州去滑雪,不过还她不太会玩,只是个能力为 1 的渣渣.贝西从 0 时刻进入滑雪场,一到 T 时刻就必须离开.滑雪场里有 N 条斜坡,第 i 条斜坡滑行一次需要 Di 分钟,要求 ...
- 使用siege进行Web压力测试
因为最近公司线上node项目出一些不稳定的情况,考虑在这方面能不能做进一步的优化,既然要做优化首先要知道问题出在哪里? 因为暂无法定位是node层问题还是api层出现问题,由于在开发环境小并发量程序运 ...
- typedef定义函数类型或函数指针
转载请标明出处: 最近在看redis的代码,发现了有关函数指针的部分,想把它记下来. 在redis中有类似下面的定义,利用typedef 定义了一个新的类型,这种类型是一个函数: typedef vo ...
- [windows驱动]标准驱动例程
[注]routine:例行程序. 1.标准驱动例程简介: 每一个内核态驱动程序都是由一系列系统定义的,标准的驱动例程组成.内核态驱动在这些标准例程中通过调用系统提供的驱动支持函数处理I/O请求包.为了 ...