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> {@Overridepublic 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 blockingprivate BoundListOperations<String, T> listOperations;//noblockingprivate 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;}@Overridepublic 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);}@Overridepublic 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 {@Overridepublic 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”,你會發現程式的控制台仍然能夠正常列印佇列資訊。
更多文章: 武漢企業目錄 JMeter壓力測試工具——環境搭建 工作的用的小指令碼(原創) 【修鍊十二】當蘿蔔+大棒失效時,我們如何更有效激勵員工。 SWTableView(CCTableView)移動清單項目到指定索引對應的cell stl string的記憶體增長策略 線上學習編程網站收集 關於使用TexturePacker打包圖片後,運行時精靈圖片會變紅,並且有異樣文字 一步步實現自己的架構系列(三):用戶端服務端通訊的實現 注入架構RoboGuice
<iframe id="iframeu1254640_0" src="http://pos.baidu.com/acom?rdid=1254640&dc=2&di=u1254640&dri=0&dis=0&dai=1&ps=5913x8&dcb=BAIDU_EXP_UNION_define&dtm=BAIDU_DUP_SETJSONADSLOT&dvi=0.0&dci=-1&dpt=none&tsr=88&tpr=1452072691177&ti=Spring-data-redis%3A%20%E5%88%86%E5%B8%83%E5%BC%8F%E9%98%9F%E5%88%97%20-%20%E8%84%9A%E6%9C%AC%E7%99%BE%E4%BA%8B%E9%80%9A&ari=1&dbv=2&drs=1&pcs=1337x719&pss=1337x5922&cfv=0&cpl=4&chi=1&cce=true&cec=GBK&tlm=1425257122&ltu=http%3A%2F%2Fwww.csdn123.com%2Fhtml%2Fblogs%2F20130616%2F22846.htm&ltr=https%3A%2F%2Fwww.baidu.com%2Flink%3Furl%3DeaAHmNKcNRPDMi0Z7iVAuHgU2Tw729bGOsLF1u7KwtRFNERJg8tHxfIBAHgGxgSzECcQNsDOm4eTFqrWAEFqNa%26wd%3D%26eqid%3Db6daff4d0001185700000003568cdeef&ecd=1&psr=1600x900&par=1538x900&pis=-1x-1&ccd=24&cja=true&cmi=6&col=zh-CN&cdo=-1&tcn=1452072691&exps=110211&qn=06472862a48c85e3&tt=1452072691088.92.113.115&feid=110211" width="960" height="90" align="center,center" vspace="0" hspace="0" marginwidth="0" marginheight="0" scrolling="no" frameborder="0" allowtransparency="true" style="border-width: 0px; border-style: initial; vertical-align: bottom; margin: 0px;"></iframe>
百度統計 <iframe scrolling="no" frameborder="0" allowtransparency="true" align="center,center" src="http://pos.baidu.com/ecom?adn=32&at=231&aurl=&cad=1&ccd=24&cec=GBK&cfv=19&ch=0&col=zh-CN&conBW=0&conOP=1&cpa=1&dai=1&dis=0&hn=4&ltr=https%3A%2F%2Fwww.baidu.com%2Flink%3Furl%3DeaAHmNKcNRPDMi0Z7iVAuHgU2Tw729bGOsLF1u7KwtRFNERJg8tHxfIBAHgGxgSzECcQNsDOm4eTFqrWAEFqNa%26wd%3D%26eqid%3Db6daff4d0001185700000003568cdeef&ltu=http%3A%2F%2Fwww.csdn123.com%2Fhtml%2Fblogs%2F20130616%2F22846.htm&lunum=6&n=94007089_cpr&pcs=1337x719&pis=10000x10000&ps=6053x8&psr=1600x900&pss=1337x6054&qn=ac064af064d6cb58&rad=&rsi0=960&rsi1=75&rsi5=4&rss0=%23FFFFFF&rss1=%23FFFFFF&rss2=%230000ff&rss3=&rss4=&rss5=&rss6=%23e10900&rss7=&scale=&skin=&slideLU_abs_pos=bottom&slideLU_in_per=1.0&slideLU_out_per=0.0&slideLU_rel_pos=left&stid=14&td_id=1656710&titFF=%E5%AE%8B%E4%BD%93&titFS=12&titTA=left&tn=baiduTlinkInlay&tpr=1452072691177&ts=1&wn=9&xuanting=0&cpro_id=u1656710_0&dtm=BAIDU_DUP2_SETJSONADSLOT&dc=2&di=u1656710&ti=Spring-data-redis%3A%20%E5%88%86%E5%B8%83%E5%BC%8F%E9%98%9F%E5%88%97%20-%20%E8%84%9A%E6%9C%AC%E7%99%BE%E4%BA%8B%E9%80%9A&tt=1452072691265.11.29.62" style="width: 960px; height: 75px;"></iframe> 為您推薦