Spring-data-redis: 分布式队列
Redis中list数据结构,具有“双端队列”的特性,同时redis具有持久数据的能力,因此redis实现分布式队列是非常安全可靠的。它类似于JMS中的“Queue”,只不过功能和可靠性(事务性)并没有JMS严格。
Redis中的队列阻塞时,整个connection都无法继续进行其他操作,因此在基于连接池设计是需要注意。
我们通过spring-data-redis,来实现“同步队列”,设计风格类似与JMS。
一.配置文件:
- <beans xmlns="http://www.springframework.org/schema/beans"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd" default-autowire="byName">
- <bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig">
- <property name="maxActive" value="32"></property>
- <property name="maxIdle" value="6"></property>
- <property name="maxWait" value="15000"></property>
- <property name="minEvictableIdleTimeMillis" value="300000"></property>
- <property name="numTestsPerEvictionRun" value="3"></property>
- <property name="timeBetweenEvictionRunsMillis" value="60000"></property>
- <property name="whenExhaustedAction" value="1"></property>
- </bean>
- <bean id="jedisConnectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory" destroy-method="destroy">
- <property name="poolConfig" ref="jedisPoolConfig"></property>
- <property name="hostName" value="127.0.0.1"></property>
- <property name="port" value="6379"></property>
- <property name="password" value="0123456"></property>
- <property name="timeout" value="15000"></property>
- <property name="usePool" value="true"></property>
- </bean>
- <bean id="jedisTemplate" class="org.springframework.data.redis.core.RedisTemplate">
- <property name="connectionFactory" ref="jedisConnectionFactory"></property>
- <property name="defaultSerializer">
- <bean class="org.springframework.data.redis.serializer.StringRedisSerializer"/>
- </property>
- </bean>
- <bean id="jedisQueueListener" class="com.sample.redis.sdr.QueueListener"/>
- <bean id="jedisQueue" class="com.sample.redis.sdr.RedisQueue" destroy-method="destroy">
- <property name="redisTemplate" ref="jedisTemplate"></property>
- <property name="key" value="user:queue"></property>
- <property name="listener" ref="jedisQueueListener"></property>
- </bean>
- </beans>
二.程序实例:
1) QueueListener:当队列中有数据时,可以执行类似于JMS的回调操作。
- public interface RedisQueueListener<T> {
- public void onMessage(T value);
- }
- public class QueueListener<String> implements RedisQueueListener<String> {
- @Override
- public void onMessage(String value) {
- System.out.println(value);
- }
- }
2) RedisQueue:队列操作,内部封装redisTemplate实例;如果配置了“listener”,那么queue将采用“消息回调”的方式执行,listenerThread是一个后台线程,用来自动处理“队列信息”。如果不配置“listener”,那么你可以将redisQueue注入到其他spring bean中,手动去“take”数据即可。
- public class RedisQueue<T> implements InitializingBean,DisposableBean{
- private RedisTemplate redisTemplate;
- private String key;
- private int cap = Short.MAX_VALUE;//最大阻塞的容量,超过容量将会导致清空旧数据
- private byte[] rawKey;
- private RedisConnectionFactory factory;
- private RedisConnection connection;//for blocking
- private BoundListOperations<String, T> listOperations;//noblocking
- private Lock lock = new ReentrantLock();//基于底层IO阻塞考虑
- private RedisQueueListener listener;//异步回调
- private Thread listenerThread;
- private boolean isClosed;
- public void setRedisTemplate(RedisTemplate redisTemplate) {
- this.redisTemplate = redisTemplate;
- }
- public void setListener(RedisQueueListener listener) {
- this.listener = listener;
- }
- public void setKey(String key) {
- this.key = key;
- }
- @Override
- public void afterPropertiesSet() throws Exception {
- factory = redisTemplate.getConnectionFactory();
- connection = RedisConnectionUtils.getConnection(factory);
- rawKey = redisTemplate.getKeySerializer().serialize(key);
- listOperations = redisTemplate.boundListOps(key);
- if(listener != null){
- listenerThread = new ListenerThread();
- listenerThread.setDaemon(true);
- listenerThread.start();
- }
- }
- /**
- * blocking
- * remove and get last item from queue:BRPOP
- * @return
- */
- public T takeFromTail(int timeout) throws InterruptedException{
- lock.lockInterruptibly();
- try{
- List<byte[]> results = connection.bRPop(timeout, rawKey);
- if(CollectionUtils.isEmpty(results)){
- return null;
- }
- return (T)redisTemplate.getValueSerializer().deserialize(results.get(1));
- }finally{
- lock.unlock();
- }
- }
- public T takeFromTail() throws InterruptedException{
- return takeFromHead(0);
- }
- /**
- * 从队列的头,插入
- */
- public void pushFromHead(T value){
- listOperations.leftPush(value);
- }
- public void pushFromTail(T value){
- listOperations.rightPush(value);
- }
- /**
- * noblocking
- * @return null if no item in queue
- */
- public T removeFromHead(){
- return listOperations.leftPop();
- }
- public T removeFromTail(){
- return listOperations.rightPop();
- }
- /**
- * blocking
- * remove and get first item from queue:BLPOP
- * @return
- */
- public T takeFromHead(int timeout) throws InterruptedException{
- lock.lockInterruptibly();
- try{
- List<byte[]> results = connection.bLPop(timeout, rawKey);
- if(CollectionUtils.isEmpty(results)){
- return null;
- }
- return (T)redisTemplate.getValueSerializer().deserialize(results.get(1));
- }finally{
- lock.unlock();
- }
- }
- public T takeFromHead() throws InterruptedException{
- return takeFromHead(0);
- }
- @Override
- public void destroy() throws Exception {
- if(isClosed){
- return;
- }
- shutdown();
- RedisConnectionUtils.releaseConnection(connection, factory);
- }
- private void shutdown(){
- try{
- listenerThread.interrupt();
- }catch(Exception e){
- //
- }
- }
- class ListenerThread extends Thread {
- @Override
- public void run(){
- try{
- while(true){
- T value = takeFromHead();//cast exceptionyou should check.
- //逐个执行
- if(value != null){
- try{
- listener.onMessage(value);
- }catch(Exception e){
- //
- }
- }
- }
- }catch(InterruptedException e){
- //
- }
- }
- }
- }
3) 使用与测试:
- public static void main(String[] args) throws Exception{
- ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("classpath:spring-redis-beans.xml");
- RedisQueue<String> redisQueue = (RedisQueue)context.getBean("jedisQueue");
- redisQueue.pushFromHead("test:app");
- Thread.sleep(15000);
- redisQueue.pushFromHead("test:app");
- Thread.sleep(15000);
- redisQueue.destroy();
- }
在程序运行期间,你可以通过redis-cli(客户端窗口)执行“lpush”,你会发现程序的控制台仍然能够正常打印队列信息。
Spring-data-redis: 分布式队列的更多相关文章
- Spring Data Redis实现消息队列——发布/订阅模式
一般来说,消息队列有两种场景,一种是发布者订阅者模式,一种是生产者消费者模式.利用redis这两种场景的消息队列都能够实现. 定义:生产者消费者模式:生产者生产消息放到队列里,多个消费者同时监听队列, ...
- Spring Data Redis—Pub/Sub(附Web项目源码)
一.发布和订阅机制 当一个客户端通过 PUBLISH 命令向订阅者发送信息的时候,我们称这个客户端为发布者(publisher). 而当一个客户端使用 SUBSCRIBE 或者 PSUBSCRIBE ...
- Spring Data Redis—Pub/Sub(附Web项目源码) (转)
一.发布和订阅机制 当一个客户端通过 PUBLISH 命令向订阅者发送信息的时候,我们称这个客户端为发布者(publisher). 而当一个客户端使用 SUBSCRIBE 或者 PSUBSCRIBE ...
- Spring Data Redis 详解及实战一文搞定
SDR - Spring Data Redis的简称. Spring Data Redis提供了从Spring应用程序轻松配置和访问Redis的功能.它提供了与商店互动的低级别和高级别抽象,使用户免受 ...
- spring data redis RedisTemplate操作redis相关用法
http://blog.mkfree.com/posts/515835d1975a30cc561dc35d spring-data-redis API:http://docs.spring.io/sp ...
- spring mvc Spring Data Redis RedisTemplate [转]
http://maven.springframework.org/release/org/springframework/data/spring-data-redis/(spring-data包下载) ...
- Spring Data Redis简介以及项目Demo,RedisTemplate和 Serializer详解
一.概念简介: Redis: Redis是一款开源的Key-Value数据库,运行在内存中,由ANSI C编写,详细的信息在Redis官网上面有,因为我自己通过google等各种渠道去学习Redis, ...
- Spring data redis的一个bug
起因 前两天上线了一个新功能,导致线上业务的缓存总是无法更新,报错也是非常奇怪,redis.clients.jedis.exceptions.JedisConnectionException: Unk ...
- spring data redis 理解
前言 Spring Data Redis project,应用了Spring概念来开发使用键值形式的数据存储的解决方案.我们(官方)提供了一个 "template" ,这是一个高级 ...
- Spring Data Redis 让 NoSQL 快如闪电(2)
[编者按]本文作者为 Xinyu Liu,文章的第一部分重点概述了 Redis 方方面面的特性.在第二部分,将介绍详细的用例.文章系国内 ITOM 管理平台 OneAPM 编译呈现. 把 Redis ...
随机推荐
- Oracle树反向查询的优化(转载)
本文系转载,http://technology.amis.nl/2005/08/11/selecting-a-pruned-tree-with-selected-nodes-and-all-their ...
- 如何使用JAVA语言抓取某个网页中的邮箱地址
现实生活中咱们常常在浏览网页时看到自己需要的信息,但由于信息过于庞大而又不能逐个保存下来. 接下来,咱们就以获取邮箱地址为例,使用java语言抓取网页中的邮箱地址 实现思路如下: 1.使用Java.n ...
- BZOJ 3230: 相似子串( RMQ + 后缀数组 + 二分 )
二分查找求出k大串, 然后正反做后缀数组, RMQ求LCP, 时间复杂度O(NlogN+logN) -------------------------------------------------- ...
- hive支持sql大全
转自:http://www.aboutyun.com/thread-7316-1-1.html 一.关系运算:1. 等值比较: = 语法:A=B 操作类型:所有基本类型 描述: 如果表达式A与表达式B ...
- leetcode 31. Next Permutation(字典序的下一个)
描述: Implement next permutation, which rearranges numbers into the lexicographically next greater per ...
- js判断微信内置浏览器
做了一个h5页面来下载app,但如果页面是用微信扫一扫打开的,点击下载按钮下载不了app,原因是微信内置浏览器屏蔽了下载链接.所以增加了检测,如果用户是用微信浏览器打开的,则提示用户使用浏览器打开.那 ...
- Java中的流程控制(一)
程序的流程控制(一) 关于Java程序的流程控制(一) 从结构化程序设计角度出发,程序有三种结构: 顺序结构 选择结构 循环结构 1.顺序结构 就是程序从上到下一行行执行,中间没有判断和跳转. 2.i ...
- (转)深入浅出Java三大框架SSH与MVC的设计模式
原址:http://www.educity.cn/java/1382738.html 现在许许多多的初学者和程序员,都在趋之若鹜地学习Web开发的宝典级框架:Struts2, Spring,Hiber ...
- codeforces 377B Preparing for the Contest 二分+优先队列
题目链接 给你m个bug, 每个bug都有一个复杂度.n个人, 每个人有两个值, 一个是能力值, 当能力值>=bug的复杂度时才可以修复这个bug, 另一个是雇佣他需要的钱,掏一次钱就可以永久雇 ...
- 6_StopWatch
6 // // ViewController.swift // StopWatch // // Created by ZC on 16/1/9. // Copyright © 2016年 ZC. Al ...