消费者端的Spring JMS 连接ActiveMQ接收生产者Oozie Server发送的Oozie作业执行结果
一,介绍
Oozie是一个Hadoop工作流服务器,接收Client提交的作业(MapReduce作业)请求,并把该作业提交给MapReduce执行。同时,Oozie还可以实现消息通知功能,只要配置好消息服务器,Oozie Server就可以把作业的执行结果发送到消息服务器上,而Client只需要订阅其感兴趣的消息即可。具体的配置参考这篇文章:Oozie 使用ActiveMQ实现 JMS通知
由于Spring内置了JMS相关的服务,因此这里记录在Spring中如何配置消费者连接ActiveMQ,从而接收生产者Oozie发送的消息。
二,Oozie Server作为生产者的相关配置
这主要在这篇文章Oozie 使用ActiveMQ实现 JMS通知 已经提到了。
其中Oozie的配置文件 oozie-default.xml中相关配置如下:
<property>
<name>oozie.jms.producer.connection.properties</name>
<value>java.naming.factory.initial#org.apache.activemq.jndi.ActiveMQInitialContextFactory;java.naming.provider.url#tcp://l
ocalhost:61616;connectionFactoryNames#ConnectionFactory</value>
</property>
<!-- JMSAccessorService --> <property> <name>oozie.service.JMSAccessorService.connectioncontext.impl</name> <value> org.apache.oozie.jms.DefaultConnectionContext </value> <description> Specifies the Connection Context implementation </description> </property>
Destination的相关配置如下,这里的Destination是一个Topic,即生产者发送消息的目的地,也是消费者取消息的地方。
<property>
<name>oozie.service.JMSTopicService.topic.name</name>
<value>
default=${username}
</value>
<description>
Topic options are ${username} or ${jobId} or a fixed string which can be specified as default or for a
particular job type.
For e.g To have a fixed string topic for workflows, coordinators and bundles,
specify in the following comma-separated format: {jobtype1}={some_string1}, {jobtype2}={some_string2}
where job type can be WORKFLOW, COORDINATOR or BUNDLE.
e.g. Following defines topic for workflow job, workflow action, coordinator job, coordinator action,
bundle job and bundle action
WORKFLOW=workflow,
COORDINATOR=coordinator,
BUNDLE=bundle
For jobs with no defined topic, default topic will be ${username}
</description>
</property>
三,在Spring中配置消费者的连接信息
这里采用JNDI连接ActiveMQ,连接信息配置如下:
<bean id="jndiTemplate" class="org.springframework.jndi.JndiTemplate">
<property name="environment">
<props>
<prop key="java.naming.factory.initial">
org.apache.activemq.jndi.ActiveMQInitialContextFactory
</prop>
<prop key="java.naming.provider.url">
tcp://192.168.121.35:61616
</prop>
<prop key="java.naming.security.principal">
system
</prop>
<prop key="java.naming.security.credentials">
manager
</prop>
</props>
</property>
</bean>
配置连接工厂:
<bean id="jndiTopicConnectionFactory" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiTemplate" ref="jndiTemplate" />
<property name="jndiName" value="ConnectionFactory" />
</bean>
我是怎么知道连接工厂的value="ConnectionFactory"的呢?由于我大部分采用的是Oozie的默认配置,根据Oozie官网提供的一个示例程序,调试出的Oozie使用的连接工厂的。
//获得Oozie中关于JMS的相关配置信息,如Transport Connectors
OozieClient oc = new OozieClient("http://192.168.121.35:11000/oozie");
JMSConnectionInfo jmsInfo = oc.getJMSConnectionInfo();
Properties jndiProperties = jmsInfo.getJNDIProperties();
Context jndiContext = new InitialContext(jndiProperties);
这段代码建立到ActiveMQ的连接上下文,调试上述代码可以看到下面的一些信息:
{java.naming.provider.url=tcp://192.168.121.35:61616,
java.naming.factory.initial=org.apache.activemq.jndi.ActiveMQInitialContextFactory,
connectionFactoryNames=ConnectionFactory}
配置Topic
<bean id="notifyTopic" class="org.apache.activemq.command.ActiveMQTopic">
<constructor-arg value="cdhfive"></constructor-arg>
</bean>
Topic就是Destination啊。由于从oozie-default.xml中得到生产者的Topic为 ${username},而我们这里的用户名为cdhfive ,故Topic的配置如上。
配置监听器
<bean id="jmsContainer"
class="org.springframework.jms.listener.DefaultMessageListenerContainer">
<property name="connectionFactory" ref="topicConnectionFactory"></property>
<property name="destinationResolver" ref="destinationResolver"></property>
<property name="concurrentConsumers" value="1"></property>
<property name="destination" ref="notifyTopic"></property>
<property name="messageListener" ref="messageListener"></property>
</bean>
concurrentConsumers,表示消费者的数量。由于使用的是Pub/Sub模型,每个Consumer都会收到同样的消息。
destination,就是Topic的地址。
messageListener,就是监听器的实现bean,该bean 实现了 javax.jms.MessageListener接口
<bean id="messageListener" class="com.schedule.tools.message.SimpleJMSReceiver" />
配置Spring 订阅者收到消息后,自动向ActiveMQ返回确认模式:一个有三种:①AUTO_ACKNOWLEDGE;②CLIENT_ACKNOWLEDGE;③DUPS_OK_ACKNOWLEDGE
设置DefaultMessageListenerContainer类的sessionAcknowledgeMode属性来配置确认模式。关于这三种确认模式在何时进行确认呢?
AUTO_ACKNOWLEDGE Automatic message acknowledgment before listener execution; no redelivery in case of exception thrown. CLIENT_ACKNOWLEDGE Automatic message acknowledgment after successful listener execution; no redelivery in case of exception thrown. DUPS_OK_ACKNOWLEDGE Lazy message acknowledgment during or after listener execution; potential redelivery in case of exception thrown.
可以看出:AUTO_ACKNOWLEDGE是在 onMessage方法调用之前,Spring就已经给ActiveMQ确认消息,并且若在onMessage方法中抛出异常了,消息不会重发。
CLIENT_ACKNOWLEDGE是在onMessage方法成功执行之后,Spring才向ActiveMQ确认消息,若在onMessage方法中抛出异常了,消息不会重发。
DUPS_OK_ACKNOWLEDGE是在onMessage方法成功执行之后,Spring才向ActiveMQ确认消息(会有延迟确认),若在onMessage方法中抛出异常了,消息可能会重发(potential redelivery)。
至此,大部分的配置已经完成了。
四,实现监听器MessageListener接口,接收消息
当有消息推送给订阅者时,javax.jms.MessageListener接口的onMessage()方法被自动调用,就可以在该方法中处理收到的消息了。
@Override
public void onMessage(Message message) {
String parentJobId = null;
String jobId = null;
String errorMessage = null;
String status = null;
Date startTime = null;
Date endTime = null;
long runTime = -1;//-1 means job run error
try {
// 普通用户作业和解释作业
if (message.getStringProperty(JMSHeaderConstants.APP_TYPE).equals(
AppType.WORKFLOW_JOB.name())) {
WorkflowJobMessage wfJobMessage = JMSMessagingUtils
.getEventMessage(message);
// 是普通作业
jobId = wfJobMessage.getId();
errorMessage = wfJobMessage.getErrorMessage();
status = wfJobMessage.getStatus().toString();
startTime = wfJobMessage.getStartTime();
endTime = wfJobMessage.getEndTime();
if(endTime != null){
runTime = endTime.getTime() - startTime.getTime();
System.out.println(jobId + "执行了:" + (endTime.getTime()-startTime.getTime())/1000 + "s");
}
//other code.....
五,参考资料
《JAVA消息服务》电子工业出版社
https://oozie.apache.org/docs/4.0.0/DG_JMSNotifications.html
消费者端的Spring JMS 连接ActiveMQ接收生产者Oozie Server发送的Oozie作业执行结果的更多相关文章
- ActiveMQ第二弹:使用Spring JMS与ActiveMQ通讯
本文章的完整代码可从我的github中下载:https://github.com/huangbowen521/SpringJMSSample.git 上一篇文章中介绍了如何安装和运行ActiveMQ. ...
- 【ActiveMQ】Spring Jms集成ActiveMQ学习记录
Spring Jms集成ActiveMQ学习记录. 引入依赖包 无论生产者还是消费者均引入这些包: <properties> <spring.version>3.0.5.REL ...
- Spring Boot连接MySQL报错“Internal Server Error”的解决办法
报错信息如下: {timestamp: "2018-06-14T03:48:23.436+0000", status: 500, error: "Internal Ser ...
- JMS之——ActiveMQ时抛出的错误Could not connect to broker URL-使用线程池解决高并发连接
转载请注明出处:http://blog.csdn.net/l1028386804/article/details/69046395 解决使用activemq时抛出的异常:javax.j ms.JMSE ...
- 【Active入门-2】ActiveMQ学习-生产者与消费者
1个生产者,1个消费者,使用Queue: 方式1: 生产者将消息发送到Queue中,退出: 然后运行消费者: . 可以看到,可以接收到消息. 方式2: 先运行消费者程序: 然后运行生产者: 消费者见下 ...
- .net core signalR 服务端强制中断用户连接
.net core signalR 服务端断开连接 { } { } *:first-child { } *:last-child { } { } { } { } { } { } { } { } { } ...
- ActiveMQ学习笔记(5)——使用Spring JMS收发消息
摘要 ActiveMQ学习笔记(四)http://my.oschina.net/xiaoxishan/blog/380446 中记录了如何使用原生的方式从ActiveMQ中收发消息.可以看出,每次 ...
- Spring JMS ActiveMQ整合(转)
转载自:http://my.oschina.net/xiaoxishan/blog/381209#comment-list ActiveMQ学习笔记(四)http://my.oschina.net/x ...
- spring集成JMS访问ActiveMQ
首先我们搭建一个spring-mvc项目,项目可以参考:spring-mvc 学习笔记 步骤: 在pom.xml中加上需要的包 修改web.xml,增加IOC容器 spring配置文件applicat ...
随机推荐
- 【原】Centos 7 下创建LVM流程
阅读目录 个主分区,1个扩展分区] 或 [4个主分区],扩展分区又可以有多个分区: window常见的分配方式: 方式1:[1个主分区(C盘)+1个扩展分区(包括3个分区,D,E, ...
- Nginx_地址重写(rewrite)_日志管理(log_format)_压缩输出_Nginx设定限速_Nginx设置反向代理及反向代理缓存
Nginx地址重写 Nginx rewrite rewrite语法规则1).变量名可以使用 "=" 或 "!=" 运算符~ 区分大小写~* 不区分大小写^~ 禁 ...
- JMM & synchronized概述(转)
根据Java语言规范中的说明,JVM系统中存在一个主内存(Main Memory),Java中所有的变量存储在主内存中,对于所有的线程是共享的(相当于黑板,其他人都可以看到的).每个线程都有自己的工作 ...
- U3d中实现A*寻路,附源文件
图片看不清楚,请点击看大图 http://pan.baidu.com/s/1pKwmOYn 写了好多,没保存,哎哎哎 空格键开始移动
- c fopen文件读写
fopen <cstdio> FILE * fopen ( const char * filename, const char * mode ); Open file Opens the ...
- (转)ZooKeeper伪分布式集群安装及使用
转自:http://blog.fens.me/hadoop-zookeeper-intro/ 前言 ZooKeeper是Hadoop家族的一款高性能的分布式协作的产品.在单机中,系统协作大都是进程级的 ...
- HTMLParser使用详解(3)- 通过Filter访问内容
HTMLParser遍历了网页的内容以后,以树(森林)结构保存了结果.HTMLParser访问结果内容的方法有两种.使用Filter和使用Visitor. (一)Filter类顾名思义,Filter就 ...
- DIY--主板跳线接法
如下图:
- [ActionScript 3.0] AS3 用于拖动对象时跟随鼠标的缓动效果
package com.fylibs.components.effects { import flash.display.DisplayObject; import flash.events.Even ...
- JDBC中的批量插入和乱码解决
字符集-乱码问题 用JDBC访问MySql数据库的时候,如果JDBC使用的字符集和MySql使用的字符集不一致,那么会导致乱码发生.解决办法当时是在使用JDBC的时候指定和数据库一样的字符集.我们可以 ...