ActiveMQ订阅模式持久化实现

我的诉求是,建一个订阅通道,然后多个客户端监听,当某个客户端掉线后,再上线的时候可以收到它没有接收到的消息。


本文主要参考了《使用Spring配置ActiveMQ的发布订阅模式》(http://nettm.iteye.com/blog/1828268),将他们复制粘贴过来,基本上就ok了。
在找到这篇文章前,《如何实现ActiveMq的Topic的持久订阅》(http://www.mytju.com/classcode/news_readNews.asp?newsID=486)给了我提示。要设置clientID啊~


我根据参考的文章编写了工程,测试后发现是ok的。并且发现了一个细节。
比如,有一个clientID=ID_1,有个通道是topic_channel。往topic_channel中发送一批消息(A批)后,首次启动ID_1的监听,ID_1没有收到。关掉ID_1的监听,再往topic_channel中发送一批消息(B批)后,再次启动ID_1的监听,收到了B批消息。这个现象说明了什么呢?说明你不仅要有自己唯一的ID(clientID)还要事先跟这个通道报告一声,说你要监听它,订阅的消息来了之后给它留一份,等着它来拿。在你报告之前产生的消息,你是拿不到的,因为没有你的份。


为了体现我真的动了脑筋,思考了。所以我发表的工程,是做了一些修改的,比如,通道名啊,ID名啊,文件名啊,还调整了一下文件结构,哈哈哈~
当然我还做了一个质的突破,我在一个工程里面做了两个接收者,监听同一个订阅通道。


实现步骤:
1、配置发送xml,applicationContext-send.xml
<?xml version="1.0" encoding="UTF-8"?>  
  
<beans xmlns="http://www.springframework.org/schema/beans"  
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"  
    xsi:schemaLocation="http://www.springframework.org/schema/beans    
         http://www.springframework.org/schema/beans/spring-beans-2.5.xsd    
         http://www.springframework.org/schema/context    
         http://www.springframework.org/schema/context/spring-context-2.5.xsd">  
  <context:property-placeholder location="classpath:/properties/jms.properties" />
  
    <!-- 配置JMS连接工厂 -->  
    <bean id="myConnectionFactory"  
        class="org.springframework.jms.connection.CachingConnectionFactory">  
        <!-- Session缓存数量 -->  
        <property name="sessionCacheSize" value="10" />  
        <property name="targetConnectionFactory">  
            <bean class="org.apache.activemq.ActiveMQConnectionFactory">  
                <!-- MQ地址 -->  
                <property name="brokerURL" value="${brokerUrl}" />  
                 <!-- 是否异步发送 -->  
                <property name="useAsyncSend" value="true" />  
            </bean>  
        </property>  
    </bean>  
  
    <!-- 发送消息的目的地(一个主题) -->  
    <bean id="myDestination" class="org.apache.activemq.command.ActiveMQTopic">  
        <!-- 设置消息主题的名字 -->  
        <constructor-arg index="0" value="${send.name}" />  
    </bean>  
  
    <!-- 配置JMS模版 -->  
    <bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate">  
        <property name="connectionFactory" ref="myConnectionFactory" />  
        <property name="defaultDestination" ref="myDestination" />  
        <!-- 订阅发布模式 -->  
        <property name="pubSubDomain" value="true" />  
        <property name="receiveTimeout" value="10000" />  
    </bean>  
</beans> 


2、编写发送java,ActiveMQsender.java

package com.by.activeMQ;

import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.Session;
import javax.jms.TextMessage;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.jms.core.JmsTemplate;
import org.springframework.jms.core.MessageCreator;

public class ActiveMQsender {
	public static void main(String[] args) {
		@SuppressWarnings("resource")
		ApplicationContext ctx = new ClassPathXmlApplicationContext(
				"ApplicationContext/applicationContext-send.xml");

		JmsTemplate jmsTemplate = (JmsTemplate) ctx.getBean("jmsTemplate");

		jmsTemplate.send(new MessageCreator() {
			public Message createMessage(Session session) throws JMSException {
				TextMessage msg = session.createTextMessage();
				// 设置消息属性
				msg.setStringProperty("mood", "happy");
				// 设置消息内容
				msg.setText("Hello World!");
				return msg;
			}
		});

		System.out.println("send end");
	}
}


3、配置接收xml,applicationContext-receive.xml
<?xml version="1.0" encoding="UTF-8"?>  
  
<beans xmlns="http://www.springframework.org/schema/beans"  
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"  
    xsi:schemaLocation="http://www.springframework.org/schema/beans    
         http://www.springframework.org/schema/beans/spring-beans-2.5.xsd    
         http://www.springframework.org/schema/context    
         http://www.springframework.org/schema/context/spring-context-2.5.xsd">  
  <context:property-placeholder location="classpath:/properties/jms.properties" />
  
  <!-- 第一个接收者 -->
    <!-- 配置JMS连接工厂 -->  
    <bean id="myConnectionFactory"  
        class="org.springframework.jms.connection.CachingConnectionFactory">  
        <!-- Session缓存数量 -->  
        <property name="sessionCacheSize" value="10" />  
        <!-- 接收者ID -->  
        <property name="clientId" value="${topic.clientId}" />  
        <property name="targetConnectionFactory">  
            <bean class="org.apache.activemq.ActiveMQConnectionFactory">  
                <!-- MQ地址 -->  
                <property name="brokerURL" value="${brokerUrl}" />  
            </bean>  
        </property>  
    </bean>  
  
    <!-- 发送消息的目的地(一个主题) -->  
    <bean id="myDestination" class="org.apache.activemq.command.ActiveMQTopic">  
        <!-- 设置消息主题的名字 -->  
        <constructor-arg index="0" value="${topic.name}" />  
    </bean>  
  
    <!-- 生产消息配置 (自己定义)-->  
    <bean id="myTopicConsumer" class="com.by.activeMQ.ActiveMQreceiver" />  
  
    <!-- 消息监听器 -->  
    <bean id="myTopicListener"  
        class="org.springframework.jms.listener.adapter.MessageListenerAdapter">  
        <constructor-arg ref="myTopicConsumer" />  
        <!-- 接收消息的方法名称 -->  
        <property name="defaultListenerMethod" value="receive" />  
        <!-- 不进行消息转换 -->  
        <property name="messageConverter"><null/></property>  
    </bean>  
  
    <!-- 消息监听容器 -->  
    <bean id="myListenerContainer"  
        class="org.springframework.jms.listener.DefaultMessageListenerContainer">  
        <property name="connectionFactory" ref="myConnectionFactory" />  
        <!-- 发布订阅模式 -->  
        <property name="pubSubDomain" value="true"/>  
        <!-- 消息持久化 -->  
        <property name="subscriptionDurable" value="true"/>  
        <property name="receiveTimeout" value="10"/>  
        <!-- 接收者ID -->  
        <property name="clientId" value="${topic.clientId}" />  
        <property name="durableSubscriptionName" value="${topic.clientId}"/>  
        <property name="destination" ref="myDestination" />  
        <property name="messageListener" ref="myTopicListener" />  
    </bean>  
    
      
  <!-- 第二个接收者 -->
  
         <!-- 配置JMS连接工厂 -->  
    <bean id="myConnectionFactory2"  
        class="org.springframework.jms.connection.CachingConnectionFactory">  
        <!-- Session缓存数量 -->  
        <property name="sessionCacheSize" value="10" />  
        <!-- 接收者ID -->  
        <property name="clientId" value="${topic2.clientId}" />  
        <property name="targetConnectionFactory">  
            <bean class="org.apache.activemq.ActiveMQConnectionFactory">  
                <!-- MQ地址 -->  
                <property name="brokerURL" value="${brokerUrl}" />  
            </bean>  
        </property>  
    </bean>  
  
    <!-- 发送消息的目的地(一个主题) -->  
    <bean id="myDestination2" class="org.apache.activemq.command.ActiveMQTopic">  
        <!-- 设置消息主题的名字 -->  
        <constructor-arg index="0" value="${topic2.name}" />  
    </bean>  
  
    <!-- 生产消息配置 (自己定义)-->  
    <bean id="myTopicConsumer2" class="com.by.activeMQ.ActiveMQreceiver2" />  
  
    <!-- 消息监听器 -->  
    <bean id="myTopicListener2"  
        class="org.springframework.jms.listener.adapter.MessageListenerAdapter">  
        <constructor-arg ref="myTopicConsumer2" />  
        <!-- 接收消息的方法名称 -->  
        <property name="defaultListenerMethod" value="receive" />  
        <!-- 不进行消息转换 -->  
        <property name="messageConverter"><null/></property>  
    </bean>  
  
    <!-- 消息监听容器 -->  
    <bean id="myListenerContainer2"  
        class="org.springframework.jms.listener.DefaultMessageListenerContainer">  
        <property name="connectionFactory" ref="myConnectionFactory2" />  
        <!-- 发布订阅模式 -->  
        <property name="pubSubDomain" value="true"/>  
        <!-- 消息持久化 -->  
        <property name="subscriptionDurable" value="true"/>  
        <property name="receiveTimeout" value="10"/>  
        <!-- 接收者ID -->  
        <property name="clientId" value="${topic2.clientId}" />  
        <property name="durableSubscriptionName" value="${topic2.clientId}"/>  
        <property name="destination" ref="myDestination2" />  
        <property name="messageListener" ref="myTopicListener2" />  
    </bean> 
  
</beans>  


4、编写接收java,ActiveMQreceiver.java
package com.by.activeMQ;

import javax.jms.JMSException;
import javax.jms.TextMessage;

import org.springframework.jms.JmsException;

public class ActiveMQreceiver {
	public void receive(TextMessage message) throws JmsException, JMSException { 
		String info = "this is receiver, "
				+ " mood is " + message.getStringProperty("mood") + ","
				+ "say " + message.getText();
        System.out.println(info);
    } 
}



5、编写另一个接收java,ActiveMQreceiver.java
package com.by.activeMQ;

import javax.jms.JMSException;
import javax.jms.TextMessage;

import org.springframework.jms.JmsException;

public class ActiveMQreceiver2 {
	public void receive(TextMessage message) throws JmsException, JMSException { 
		String info = "this is receiver2,"
				+ " mood is " + message.getStringProperty("mood") + ","
				+ "say " + message.getText();
        System.out.println(info);
    } 
}



6、编写一个main,开启接收监听,openReceive.java
package com.by.activeMQ;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class openReceive {

	public static void main(String[] args) {
		@SuppressWarnings({ "unused", "resource" })
		ApplicationContext ctx = new ClassPathXmlApplicationContext("ApplicationContext/applicationContext-receive.xml");  
        while(true) {  
        } 
	}

}



7、编写一个配置文件,jms.properties

#send
send.name=Topic_Mood

#receive
topic.name=Topic_Mood
topic.clientId=client_LiLei

topic2.name=Topic_Mood
topic2.clientId=client_HanMei

#url
brokerUrl=failover:(tcp://10.0.0.232:61616)?initialReconnectDelay=1000

8、pom里面添加activeMQ的依赖

<dependency>
	<groupId>org.apache.activemq</groupId>
	<artifactId>activemq-pool</artifactId>
	<version>5.11.1</version>
</dependency>
<dependency>
	<groupId>org.apache.commons</groupId>
	<artifactId>commons-pool2</artifactId>
	<version>2.3</version>
</dependency>
<dependency>
	<groupId>org.springframework</groupId>
	<artifactId>spring-jms</artifactId>
	<version>4.0.0.RELEASE</version>
</dependency>

<dependency>
	<groupId>org.apache.activemq</groupId>
	<artifactId>activemq-all</artifactId>
	<version>5.11.1</version>
</dependency>



耶,运行就ok了。
发送消息的输出是这样的:
2016-08-05 11:27:19 [ main:0 ] - [ INFO ] Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@16011db4: startup date [Fri Aug 05 11:27:19 CST 2016]; root of context hierarchy
2016-08-05 11:27:19 [ main:31 ] - [ INFO ] Loading XML bean definitions from class path resource [ApplicationContext/applicationContext-send.xml]
2016-08-05 11:27:19 [ main:187 ] - [ INFO ] Loading properties file from class path resource [properties/jms.properties]
2016-08-05 11:27:19 [ main:392 ] - [ INFO ] Established shared JMS Connection: ActiveMQConnection {id=ID:MDG42V9PSU28IKA-60542-1470367639797-1:1,clientId=null,started=false}
2016-08-05 11:27:19 [ ActiveMQ Task-1:467 ] - [ INFO ] Successfully connected to tcp://10.0.0.232:61616
send end


接收消息的输出是这样的:
2016-08-05 11:28:04 [ ActiveMQ Task-1:490 ] - [ INFO ] Successfully connected to tcp://10.0.0.232:61616
2016-08-05 11:28:04 [ main:498 ] - [ INFO ] Established shared JMS Connection: ActiveMQConnection {id=ID:MDG42V9PSU28IKA-60544-1470367684739-1:1,clientId=client_LiLei,started=false}
2016-08-05 11:28:04 [ ActiveMQ Task-1:504 ] - [ INFO ] Successfully connected to tcp://10.0.0.232:61616
2016-08-05 11:28:04 [ main:509 ] - [ INFO ] Established shared JMS Connection: ActiveMQConnection {id=ID:MDG42V9PSU28IKA-60544-1470367684739-3:1,clientId=client_HanMei,started=false}
this is receiver2, mood is happy,say Hello World!
this is receiver,  mood is happy,say Hello World!


啦啦啦,不知道大家注意了没有,配置另一个接收者就是,把第一个接收者的配置复制,然后添加个2,再把接收类复制,添加个2,就搞定了。哈哈哈~这种方式也适用于mongodb啊这种配置。在一个工程里面操作两个mongodb数据库。


注:我将代码上传到了csdn。



  • 3
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
### 回答1: Kettle ActiveMQ是一种基于开源的消息队列系统,它是Apache软件基金会的项目之一。它是一个灵活、可扩展和高性能的消息中间件,常被用于实现异步通信和解决高并发的消息传递需求。 Kettle ActiveMQ具有以下特点: 1. 可靠性:Kettle ActiveMQ采用了持久化机制,即使在消息传递过程中发生故障,消息也不会丢失。它能够在网络中断或节点宕机后重新连接,并确保消息被可靠地传递。 2. 高性能:Kettle ActiveMQ使用高效的消息传递协议,能够支持高并发、大规模的消息传递。它采用了多线程和异步处理的方式,以提高系统的吞吐量和响应速度。 3. 可扩展性:Kettle ActiveMQ支持水平扩展和集群部署,可以根据业务需求动态增加消息队列的节点数量,以满足高负载的需求。它还支持多种通信协议,包括TCP、HTTP和WebSocket等,以便与各种应用和系统进行集成。 4. 管理和监控:Kettle ActiveMQ提供了一套完善的管理和监控工具,可以方便地对消息队列进行配置、监控和管理。它提供了Web界面和命令行工具,可以实时查看队列状态、消息流量和性能指标等。 5. 可靠性传输:Kettle ActiveMQ支持各种消息传递模式,包括点对点和发布订阅模式。它提供了消息过滤、事务管理和消息转发等功能,可以确保消息的可靠传输和按需消费。 总之,Kettle ActiveMQ是一个功能强大、易用且可靠的消息队列系统,它广泛应用于企业级应用开发、大数据处理、分布式系统以及互联网应用等领域,为应用程序之间的通信提供了高效、可靠和可扩展的解决方案。 ### 回答2: Kettle是一种开源的ETL工具,用于数据的抽取、转换和加载。而ActiveMQ是一种开源的消息中间件,用于实现消息的传递和异步通信。这两个工具在数据处理和通信方面具有不同的功能。 Kettle可以通过其强大的转换功能,从不同的数据源中提取数据,并进行各种数据处理操作,例如清洗、聚合、转换等。通过Kettle,可以将不同格式的数据整合到一起,为后续的数据分析和业务处理提供了方便。 ActiveMQ则专注于解决分布式系统中的消息通信问题。当系统中的不同模块需要进行异步通信时,ActiveMQ可以提供可靠且快速的消息传递机制。它支持多种通信协议,如AMQP、STOMP等,也提供了丰富的特性,如消息队列、发布-订阅模式等。 结合Kettle和ActiveMQ可以实现更强大的数据处理和通信功能。例如,可以使用Kettle从各个数据源中获取数据,然后将数据通过ActiveMQ发送到目标系统进行处理。这样可以实现异步处理,提高系统的响应速度和可伸缩性。 另外,Kettle也提供了与ActiveMQ的集成插件,可以直接在Kettle中配置和管理ActiveMQ,方便用户进行数据传输和消息通信的配置和管理。 总之,Kettle和ActiveMQ分别在数据处理和通信方面发挥了不可替代的作用。它们的结合可以实现更加灵活、高效的数据处理和通信机制,为企业的数据处理和系统集成提供了有力的支持。 ### 回答3: Kettle是一个开源的ETL工具,用于数据抽取、转换和加载。而ActiveMQ是一个基于Java消息传递中间件的解决方案。 在Kettle中使用ActiveMQ,可以实现数据流的异步处理和消息的发布与订阅。Kettle通过ActiveMQ的队列(Queue)和主题(Topic)机制,实现数据的可靠传输和实时处理。 在数据抽取方面,Kettle可以通过ActiveMQ的消息队列,异步地抽取源数据,并以消息的方式传递到目标端,实现异步数据处理。这样可以提高数据的处理效率,同时减少数据传输的延迟。 在数据转换方面,Kettle可以将数据转换成消息,通过ActiveMQ的队列发送出去。接收者可以异步地处理这些消息,并将处理结果返回给Kettle。这样可以实现分布式数据转换和处理,提高系统的并发能力和可扩展性。 在数据加载方面,Kettle可以通过ActiveMQ的主题机制,将数据以消息的形式发布到订阅者。订阅者可以按需订阅感兴趣的数据,并进行加载和处理。这样可以实现实时数据加载和更新,支持复杂的数据流处理需求。 总之,Kettle和ActiveMQ的结合,可以实现ETL流程的高效处理和实时数据交互。这种解决方案在大数据处理和实时数据分析等场景中具有广泛的应用前景。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值