基于ActiveMQ 的发布/订阅(Pub/Sub) Chat 示例,上传了源码
来源:互联网 发布:淘宝订单要上传身份证 编辑:程序博客网 时间:2024/06/07 23:01
转自:http://www.iteye.com/topic/836509
环境需求:
1. JDK 1.5 或者以上
2. Apache Ant, 在写本文时,用的是 Ant 1.7.1
3. ActiveMQ, 在写本文时,用的是 Apache ActiveMQ 5.4.1
技术需求:
1. JMS(Java Message Service)
2. JNDI(Java Naming and Directory Interface)
在JMS的“发布/订阅(pub/sub)”模型中,消息的发布者(Publisher)通过主题(Topic)发布消息,订阅者(Subscriber)通过订阅主题获取消息。 一个主题可以同时有多个订阅者. 通过这种方式我们可以实现广播式(broadcast)消息。
为了更好的理解"发布/订阅(Pub/Sub)"模式,我在《Java消息服务器 第二版》上找到了一个很好的例子来说明他的使用。不过书上只提供了相关代码供我们理解,没有讲述整个创建过程,在这里打算记录下整个构建实例的过程:
1. 创建项目目录入下图所示,并将activemq-all-*.jar 复制到项目的classpath中:
2. 编写Chat代码:
- public class Chatimplements MessageListener {
- private TopicSession pubSession;
- private TopicPublisher pub;
- private TopicConnection conn;
- private String username;
- public Chat(String topicFactory, String topicName, String username)
- throws NamingException, JMSException {
- // 创建 JNDI context
- InitialContext ctx = new InitialContext();
- //1. 创建 TopicConnectionFacotry
- TopicConnectionFactory factory = (TopicConnectionFactory) ctx
- .lookup(topicFactory);
- //2. 创建 TopicConnection
- TopicConnection connection = factory.createTopicConnection();
- //3. 根据 Connection 创建 JMS 会话
- TopicSession pubSession = (TopicSession) connection.createSession(
- false, Session.AUTO_ACKNOWLEDGE);
- TopicSession subSession = (TopicSession) connection.createSession(
- false, Session.AUTO_ACKNOWLEDGE);
- //4. 创建 Topic
- Topic topic = (Topic) ctx.lookup(topicName);
- //5. 创建 发布者 和 订阅者
- TopicPublisher pub = pubSession.createPublisher(topic);
- TopicSubscriber sub = subSession.createSubscriber(topic, null, true);
- //6. 为发布者设置消息监听
- sub.setMessageListener(this);
- this.conn = connection;
- this.pub = pub;
- this.pubSession = pubSession;
- this.username = username;
- //7. 开启JMS连接
- connection.start();
- }
- protected void writeMessage(String txt) {
- try {
- TextMessage message = pubSession.createTextMessage();
- message.setText(username + ": " + txt);
- pub.publish(message);
- } catch (JMSException e) {
- e.printStackTrace();
- }
- }
- public void onMessage(Message msg) {
- TextMessage txtMsg = (TextMessage) msg;
- try {
- System.out.println(txtMsg.getText());
- } catch (JMSException e) {
- e.printStackTrace();
- }
- }
- public void close()throws JMSException {
- this.conn.close();
- }
- public staticvoid main(String[] args) throws NamingException,
- JMSException, IOException {
- if (args.length != 3) {
- System.out.println("Factory, Topic, or username missing");
- }
- Chat chat = new Chat(args[0], args[1], args[2]);
- BufferedReader cmd = new BufferedReader(
- new InputStreamReader(System.in));
- while (true) {
- String s = cmd.readLine();
- if (s.equalsIgnoreCase("exit")) {
- chat.close();
- System.exit(0);
- } else {
- chat.writeMessage(s);
- }
- }
- }
- }
3.由于里我们使用了JNDI, 所以我们需要编辑jndi.properties。内容如下:
- # START SNIPPET: jndi
- java.naming.factory.initial = org.apache.activemq.jndi.ActiveMQInitialContextFactory
- # use the following property to configure the default connector
- java.naming.provider.url = tcp://localhost:61616
- java.naming.security.principal=system
- java.naming.security.credentials=manager
- # use the following property to specify the JNDI name the connection factory
- # should appear as.
- #connectionFactoryNames = connectionFactory, queueConnectionFactory, topicConnectionFactry
- connectionFactoryNames = topicConnectionFactry
- # register some queues in JNDI using the form
- # queue.[jndiName] = [physicalName]
- #queue.MyQueue = example.ChatQue
- topic.chat = example.chat
- # register some topics in JNDI using the form
- # topic.[jndiName] = [physicalName]
- #topic.MyTopic = example.ChatTop
- # END SNIPPET: jndi
4. 到这里已经基本完成Chat 编码工作,使用如下指令即可运行这个示例:
不过如果没有设置相关classpath,是不可能通过这个指令来成功运行这个Demo,在这里我打算使用Ant来帮我完成这个工作
5. 编写build.xml脚本如下:
- <?xml version="1.0"encoding="utf-8"?>
- <project name="chat"default="run"basedir=".">
- <propertyname="src.dir"value="src"/>
- <propertyname="build.dir"value="build"/>
- <propertyname="classes.dir"value="${build.dir}/classes"/>
- <propertyname="jar.dir"value="${build.dir}/jar"/>
- <propertyname="lib.dir"value="libs"/>
- <!-- 设置main函数所在类 -->
- <propertyname="main-class"value="com.dayang.jms.chat.Chat"/>
- <!-- 定义classpath -->
- <path id="classpath">
- <filesetdir="${lib.dir}"includes="**/*.jar"/>
- </path>
- <!-- 创建构建目录,用于存放构建生成的文件 -->
- <targetname="init">
- <mkdirdir="${build.dir}"/>
- </target>
- <!-- 编译 -->
- <targetname="compile"depends="init">
- <mkdirdir="${classes.dir}"/>
- <javacsrcdir="${src.dir}"destdir="${classes.dir}"
- classpathref="classpath"/>
- <!-- copy properties file to classpath -->
- <copytodir="${classes.dir}">
- <filesetdir="${src.dir}"excludes="**.*.jar"/>
- </copy>
- </target>
- <!-- 打包 -->
- <targetname="jar"depends="compile">
- <mkdirdir="${jar.dir}"/>
- <jardestfile="${jar.dir}/${ant.project.name}.jar"
- basedir="${classes.dir}">
- <manifest>
- <attributename="Main-Class"value="${main-class}"/>
- </manifest>
- </jar>
- </target>
- <!-- 运行client1 -->
- <targetname="run1"depends="jar">
- <javafork="true"classname="${main-class}">
- <argvalue="topicConnectionFactry"/>
- <argvalue="chat"/>
- <argvalue="client1"/>
- <classpath>
- <pathrefid="classpath"/>
- <pathlocation="${jar.dir}/${ant.project.name}.jar"/>
- </classpath>
- </java>
- </target>
- <!-- 运行client2 -->
- <targetname="run2"depends="jar">
- <javafork="true"classname="${main-class}">
- <argvalue="topicConnectionFactry"/>
- <argvalue="chat"/>
- <argvalue="client2"/>
- <classpath>
- <pathrefid="classpath"/>
- <pathlocation="${jar.dir}/${ant.project.name}.jar"/>
- </classpath>
- </java>
- </target>
- <targetname="clean">
- <deletedir="${build.dir}"/>
- </target>
- <targetname="clean-build"depends="clean,jar"/>
- </project>
6. 打开两个控制台窗口,分别使用ant run1 和 ant run2 指令来运行程序, 如果成功我们将看到如下结果:
写在最后:
这个示例仅仅简单的说了JMS 发布/订阅 API的基本使用,更多特性需要在以后的使用中进行摸索。
发布/订阅 除了能够提供“1对多”的消息专递方式之外,还提供了消息持久化的特性。他允许订阅者在上线后接收离线时的消息,关于这部分特性,以及“发布/订阅”的应用场景打算在以后的文章中慢慢阐述。
参考资料:
1. JMS: http://baike.baidu.com/view/157103.htm
2. ActiveMQ: http://baike.baidu.com/view/433374.htm
3. JNDI http://baike.baidu.com/view/209575.htm
4. 《Java消息服务器 第二版》
5. Ant Manual http://ant.apache.org/manual/index.html
2011-05-18: 新增加了Demo的源代码, 需要的可以下载附件JSMDemo.rar
JMSDemo工程目录结构如下:
- 基于ActiveMQ 的发布/订阅(Pub/Sub) Chat 示例,上传了源码
- Pub/Sub 发布订阅
- 发布/订阅(Pub/Sub)
- Redis的发布/订阅(pub/sub)
- JMS发布订阅(Pub/Sub)模式示例
- redis源码分析之发布订阅(pub/sub)
- zeromq/jzmq 基于信封-内容的pub/sub发布订阅java代码
- 简单的WCF发布-订阅(Pub/Sub)服务
- Redis Pub发布/sub订阅实现机制
- 9.Redis发布及订阅(pub/sub)
- Redis发布及订阅消息(pub/sub)
- Redis发布与订阅(pub/sub)
- Redis--pub/sub(发布与订阅)
- (十一)redis 发布与订阅(pub/sub)
- ActiveMq--Pub/Sub的使用
- [ActiveMQ实战]基于JMS的pub/sub传播机制
- linux下使用hiredis异步API实现sub/pub消息订阅和发布的功能
- linux下使用hiredis异步API实现sub/pub消息订阅和发布的功能
- javacript 弹窗显示欢迎 来自哪哪 用户
- OpenStack与KVM的区别与联系
- (转载)深度解析IOS开发中编码转换方法
- memcmp与strncmp函数
- 连接文件LINK
- 基于ActiveMQ 的发布/订阅(Pub/Sub) Chat 示例,上传了源码
- window phone WebClient和HttpWebRequest 并解决gb2312乱码问题
- android APK签名
- 三、第一个cocos2d程序的代码分析
- c++空指针赋初值
- Java序列化问题总结
- 中国 外包 2012(zz.IS2120@BG57IV3)
- py2exe使用
- 删除字符串开始及末尾的空白符,并且把数组中间的多个空格(如果有)