一、发布和订阅机制

  当一个客户端通过 PUBLISH 命令向订阅者发送信息的时候,我们称这个客户端为发布者(publisher)。

  而当一个客户端使用 SUBSCRIBE 或者 PSUBSCRIBE 命令接收信息的时候,我们称这个客户端为订阅者(subscriber)。

为了解耦发布者(publisher)和订阅者(subscriber)之间的关系,Redis 使用了 channel (频道)作为两者的中介 —— 发布者将信息直接发布给 channel ,而 channel 负责将信息发送给适当的订阅者,发布者和订阅者之间没有相互关系,也不知道对方的存在

注意:Redis的Pub Sub功能(或许是暂时)不支持持久化,意思就是消息在管道中是即发即失的,Subscriber端一收到消息,消息即从管道中删除。所以如果是对消息的准确性要求比较高或者是有持久化的需求,Redis就不是那么合适了,期待以后的版本加入持久化功能。

二、Pub/Sub的作用

其实从Pub/Sub的机制来看,它更像是一个广播系统,多个Subscriber可以订阅多个Channel,多个Publisher可以往多个Channel中发布消息。可以这么简单的理解:

Subscriber:收音机(只不过这个收音机可以收到多个频道,并以队列方式显示)

Publisher:电台(电台可以往不同的FM频道中发消息)

Channel:不同频率的FM频道

所以根据这个理解,那么我觉得有几种用法是比较可取的:

  1.一个Publisher,多个Subscriber:

  如下图所示,可以作为消息队列或者消息管道。

  主要应用:通知、公告。

  2.多个Publisher,一个Subscriber:

  可以将PubSub做成独立的HTTP接口,各应用程序作为Publisher向Channel中发送消息,Subscriber端收到消息后执行相应的业务逻辑,比如写数据库,显示等等。

  主要应用:排行榜、投票、计数。

3.多个Publisher,多个Subscriber

图就不上了,故名思议,就是可以向不同的Channel中发送消息,由不同的Subscriber接收。

主要应用:群聊、聊天。

可参考Spring data redis主页的开源项目retwisj。

Github地址:https://github.com/spring-projects/spring-data-keyvalue-examples/tree/master/retwisj

从上述几种用法来看,根据不同的限制条件,限制Publisher、Subscriber和Channel的数量,可以实现不同的功能,其实完全可以把Pub/Sub理解为Socket编程,用Socket也可以实现上述功能,但是Redis提供了相应的封装和底层实现,不管是安全性、健壮性的等各方面都有不错的表现,以及未来的一些拓展,个人觉得Redis是个不错的选择。

三、Demo演示:

因为我的上一篇博客Spring Data Redis简介以及项目Demo,RedisTemplate和 Serializer详解,已经演示了Spring Data Redis的基本配置和使用,所以这里就只贴上Pub/Sub的重要代码,读者可以阅读上篇博客或者下载源码。

Pub/Sub配置(XMl):

  1. <!-- SDR Pub/Sub配置 -->
  2. <!-- SubServiceImpl是实现了MessageListener接口的类,MessageListener接口中定义了onMessage方法,也就是接收消息的方法,每当Channel中有消息,onMessage方法会被自动调用, -->
  3. <bean id="messageListener" class="com.chr.service.impl.SubServiceImpl">
  4. </bean>
  5.  
  6. <!-- 可以有多个messageListener,每个messageListener必须注册到RedisMessageListenerContainer中,读者可参阅API文档 -->
  7. <bean id="messageContainer"
  8. class="org.springframework.data.redis.listener.RedisMessageListenerContainer"
  9. destroy-method="destroy">
  10. <property name="connectionFactory" ref="connectionFactory" />
  11. <!--<property name="taskExecutor"> <bean class="org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler">
  12. <property name="poolSize" value="3"></property> </bean> </property>
  13. 此处可以定义Executor,参阅java.util.concurrent.Executor-->
  14. <property name="messageListeners">
  15. <map>
  16. <entry key-ref="messageListener">
  17. <ref bean="channelTopic" />
  18. </entry>
  19. </map>
  20. </property>
  21. </bean>
  22.  
  23. <!-- Channel设置 -->
  24. <bean id="channelTopic" class="org.springframework.data.redis.listener.ChannelTopic">
  25. <constructor-arg value="user:topic" />
  26. </bean>

在代码中可以看到subServiceImpl实现类被手动注册到配置文件中,这样可能会使代码混乱,并且会带来一些问题,比如需要使用注解自动注入rankService,但是因为Spring配置中,XML的优先级大于Annotation,所以subServiceImpl中的rankService不能被@Autowired。

那么解决办法有两种:

  1.在配置文件中(messageLisener bean前)加入:

  1. <!-- 类扫描器 -->
  2.  
  3. <context:component-scan base-package="com.songod.service" />

这样Spring会先扫描Annotation,创建rankService bean,之后再注入messageLisener。

  2.在messageContainer bean中,只注入connectionFactory,不注入messageLisener和channelTopic。 之后在Controller中手动注入,调用addMessageListener(MessageListener listener, Topic topic)方法手动注入,但是注意只能注入一次,可以设置Flag判断。

PubServiceImpl:

  1. @Service
  2. public class PubServiceImpl implements PubService {
  3. @Resource(name="stringRedisTemplate")
  4. private StringRedisTemplate stringRedisTemplate;
  5.  
  6. private String channelTopic = "user:topic";
  7.  
  8. /*发布消息到Channel*/
  9. public void Publisher(String message) {
  10. stringRedisTemplate.convertAndSend(channelTopic, message);
  11. }
  12. }

我这里用的是StringRedisTemplate,读者可以使用RedisTemplate设置其它序列化方式,可以看我的上一篇博客。

SubServiceImpl:

  1. public class SubServiceImpl implements SubService {
  2. @Autowired
  3. private ChannelTopic channelTopic;
  4.  
  5. private MessageList messageList = new MessageList();
  6.  
  7. public void onMessage(Message message, byte[] pattern) {
  8. System.out.println(message.toString() + " " + channelTopic.getTopic());
  9. messageList.add(message.toString());
  10. }
  11.  
  12. public MessageList getMessageList() {
  13. return messageList;
  14. }
  15. }

主要是onMessage方法,可以在此方法中将message传入其它业务逻辑中进行处理。

四、Demo运行:

Publish:

Subscrib:

五、项目源码:

redis-web-pubsub

Spring Data Redis—Pub/Sub(附Web项目源码)的更多相关文章

  1. Spring mvc Data Redis—Pub/Sub(附Web项目源码)

    一.发布和订阅机制 当一个客户端通过 PUBLISH 命令向订阅者发送信息的时候,我们称这个客户端为发布者(publisher). 而当一个客户端使用 SUBSCRIBE 或者 PSUBSCRIBE ...

  2. Spring Data Redis—Pub/Sub(附Web项目源码) (转)

    一.发布和订阅机制 当一个客户端通过 PUBLISH 命令向订阅者发送信息的时候,我们称这个客户端为发布者(publisher). 而当一个客户端使用 SUBSCRIBE 或者 PSUBSCRIBE ...

  3. 【持久化框架】SpringMVC+Spring4+Mybatis3集成,开发简单Web项目+源码下载

    上篇博文我们介绍了mybatis的基本概念与原理,这篇博文我们通过Spring与Mybatis集成,开发一个简单用户增删改查的Web项目. 基本准备工作 1.安装JDK1.6以上版本,安装与配置 2. ...

  4. Java eclipse下 Ant build.xml实例详解 附完整项目源码

    在有eclipse集成环境下ant其实不是很重要,但有些项目需要用到,另外通过eclipse来学习和理解ant是个很好的途径,所以写他demo总结下要点,希望能够帮到大家. 一.本人测试环境eclip ...

  5. Spring Data Redis简介以及项目Demo,RedisTemplate和 Serializer详解

    一.概念简介: Redis: Redis是一款开源的Key-Value数据库,运行在内存中,由ANSI C编写,详细的信息在Redis官网上面有,因为我自己通过google等各种渠道去学习Redis, ...

  6. 关于在项目中使用spring data redis与jedis的选择

    项目中需要用到redis,主要用来作为缓存,redis的客户端有两种实现方式,一是可以直接调用jedis来实现,二是可以使用spring data redis,通过spring的封装来调用. 应该使用 ...

  7. spring mvc Spring Data Redis RedisTemplate [转]

    http://maven.springframework.org/release/org/springframework/data/spring-data-redis/(spring-data包下载) ...

  8. Spring Data Redis 让 NoSQL 快如闪电(2)

    [编者按]本文作者为 Xinyu Liu,文章的第一部分重点概述了 Redis 方方面面的特性.在第二部分,将介绍详细的用例.文章系国内 ITOM 管理平台 OneAPM 编译呈现. 把 Redis ...

  9. Spring Boot使用Spring Data Redis操作Redis(单机/集群)

    说明:Spring Boot简化了Spring Data Redis的引入,只要引入spring-boot-starter-data-redis之后会自动下载相应的Spring Data Redis和 ...

随机推荐

  1. AjaxManager的实现

    在NeralJS思路整理一章中我们提到过实用ajax管理模块控制ajax请求,以减少ajax请求数量,优化加载,以下是ajax模块的实现,我已经确保经历简单. /** * Created by wil ...

  2. mysql怎么限制某些查询语句的执行?

    mysql怎么限制某些查询语句的执行? 比如某些sql语句执行时间很长,超过10s,怎么样超过10s就不让其执行? 后续更新中...

  3. CSS3 2D转换

    CSS3 转换 通过CSS3转换,我们能够对元素进行移动.缩放.转动.拉长或拉伸. 它如何工作? 转换是是元素改变形状.尺寸和位置的一种效果. 你可以使用2D或3D转换你的元素. 浏览器支持 属性 浏 ...

  4. sql 判断表、列、视图等是否存在

    1 判断数据库是否存在 if exists (select * from sys.databases where name = '数据库名')     drop database [数据库名] 2 判 ...

  5. Eclipse搭建struts2环境

    搭建struts2环境 大的方面分为三步: 1. 加入jar包 2. 在web.xml中配置struts2 3. 添加struts2的配置文件struts.xml 下面是详细步骤: 1. 新建一个Dy ...

  6. Ubuntu小私房(4)--Linux系统目录结构

    Linux目录结构是Linux学习者必须了解的知识,Linux的目录与Windows又有很大的不同,所以搞清楚Linux目录结构是关键. Linux文件类型 (部分转自ChinaBytel) linu ...

  7. MySQL查询执行的基础

    当希望MySQL能够以更高的性能运行查询时,最好的办法就是弄清楚MySQL是如何优化和执行查询的.一旦理解这一点,很多查询优化实际上就是遵循一些原则让优化器能够按照预想的合理的方式运行. 换句话说,是 ...

  8. android 写文件权限

    首先,在manifest.xml中添加user permission:<uses-permission android:name="android.permission.WRITE_E ...

  9. BZOJ3391: [Usaco2004 Dec]Tree Cutting网络破坏

    3391: [Usaco2004 Dec]Tree Cutting网络破坏 Time Limit: 1 Sec  Memory Limit: 128 MBSubmit: 47  Solved: 37[ ...

  10. 设计模式(十二): Flyweight享元模式 -- 结构型模式

    说明: 相对于其它模式,Flyweight模式在PHP实现似乎没有太大的意义,因为PHP的生命周期就在一个请求,请求执行完了,php占用的资源都被释放.我们只是为了学习而简单做了介绍. 1. 概述 面 ...