生活随笔
收集整理的這篇文章主要介紹了
Redis整合Spring结合使用缓存实例(转)
小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
? ? ? ? ?林炳文Evankaka原創(chuàng)作品。轉(zhuǎn)載請注明出處http://blog.csdn.net/evankaka
? ? ? ? ?摘要:本文介紹了如何在Spring中配置redis,并通過Spring中AOP的思想,將緩存的方法切入到有需要進入緩存的類或方法前面。
一、Redis介紹
什么是Redis?
? ? ? redis是一個key-value存儲系統(tǒng)。和Memcached類似,它支持存儲的value類型相對更多,包括string(字符串)、list(鏈表)、set(集合)、zset(sorted set --有序集合)和hash(哈希類型)。這些數(shù)據(jù)類型都支持push/pop、add/remove及取交集并集和差集及更豐富的操作,而且這些操作都是原子性的。在此基礎上,redis支持各種不同方式的排序。與memcached一樣,為了保證效率,數(shù)據(jù)都是緩存在內(nèi)存中。區(qū)別的是redis會周期性的把更新的數(shù)據(jù)寫入磁盤或者把修改操作寫入追加的記錄文件,并且在此基礎上實現(xiàn)了master-slave(主從)同步。
它有什么特點?
(1)Redis數(shù)據(jù)庫完全在內(nèi)存中,使用磁盤僅用于持久性。
(2)相比許多鍵值數(shù)據(jù)存儲,Redis擁有一套較為豐富的數(shù)據(jù)類型。
(3)Redis可以將數(shù)據(jù)復制到任意數(shù)量的從服務器。
Redis 優(yōu)勢?
?(1)異常快速:Redis的速度非常快,每秒能執(zhí)行約11萬集合,每秒約81000+條記錄。
?(2)支持豐富的數(shù)據(jù)類型:Redis支持最大多數(shù)開發(fā)人員已經(jīng)知道像列表,集合,有序集合,散列數(shù)據(jù)類型。這使得它非常容易解決各種各樣的問題,因為我們知道哪些問題是可以處理通過它的數(shù)據(jù)類型更好。
(3)操作都是原子性:所有Redis操作是原子的,這保證了如果兩個客戶端同時訪問的Redis服務器將獲得更新后的值。
(4)多功能實用工具:Redis是一個多實用的工具,可以在多個用例如緩存,消息,隊列使用(Redis原生支持發(fā)布/訂閱),任何短暫的數(shù)據(jù),應用程序,如Web應用程序會話,網(wǎng)頁命中計數(shù)等。
Redis 缺點?
(1)單線程
(2)耗內(nèi)存
二、使用實例
本文使用maven+eclipse+sping
1、引入jar包
?
[html]?view plain
?copy ???? <dependency>??????<groupId>org.springframework.data</groupId>?? ????<artifactId>spring-data-redis</artifactId>?? ????<version>1.6.1.RELEASE</version>?? </dependency>??<dependency>??????<groupId>redis.clients</groupId>?? ????<artifactId>jedis</artifactId>?? ????<version>2.7.3</version>?? </dependency>????? 2、配置bean
?
在application.xml加入如下配置
?
[html]?view plain
?copy ???<bean?id="poolConfig"?class="redis.clients.jedis.JedisPoolConfig"?>?? ?????????<property?name="maxIdle"?value="${redis.maxIdle}"?/>?? ?????????<property?name="maxWaitMillis"?value="${redis.maxWait}"?/>?? ?????????<property?name="testOnBorrow"?value="${redis.testOnBorrow}"?/>?? ???</bean?>?? ?? ???<bean?id="connectionFactory"??class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory"?>?? ?????????<property?name="poolConfig"?ref="poolConfig"?/>?? ?????????<property?name="port"?value="${redis.port}"?/>?? ?????????<property?name="hostName"?value="${redis.host}"?/>?? ?????????<property?name="password"?value="${redis.password}"?/>?? ?????????<property?name="timeout"?value="${redis.timeout}"?></property>?? ???</bean?>?? ???<bean?id="redisTemplate"?class="org.springframework.data.redis.core.RedisTemplate"?>?? ?????????<property?name="connectionFactory"?ref="connectionFactory"?/>?? ?????????<property?name="keySerializer"?>?? ?????????????<bean?class="org.springframework.data.redis.serializer.StringRedisSerializer"?/>?? ?????????</property>?? ?????????<property?name="valueSerializer"?>?? ?????????????<bean?class="org.springframework.data.redis.serializer.JdkSerializationRedisSerializer"?/>?? ?????????</property>?? ???</bean?>?? ????????? ???<bean?id="methodCacheInterceptor"?class="com.mucfc.msm.common.MethodCacheInterceptor"?>?? ?????????<property?name="redisUtil"?ref="redisUtil"?/>?? ???</bean?>?? ???<bean?id="redisUtil"?class="com.mucfc.msm.common.RedisUtil"?>?? ?????????<property?name="redisTemplate"?ref="redisTemplate"?/>?? ???</bean?>?? 其中配置文件redis一些配置數(shù)據(jù)redis.properties如下:
?
?
[plain]?view plain
?copy #redis中心??redis.host=10.75.202.11??redis.port=6379??redis.password=123456??redis.maxIdle=100??redis.maxActive=300??redis.maxWait=1000??redis.testOnBorrow=true??redis.timeout=100000????#?不需要加入緩存的類??targetNames=xxxRecordManager,xxxSetRecordManager,xxxStatisticsIdentificationManager??#?不需要緩存的方法??methodNames=????#設置緩存失效時間??com.service.impl.xxxRecordManager=?60??com.service.impl.xxxSetRecordManager=?60??defaultCacheExpireTime=3600????fep.local.cache.capacity?=10000?? 要掃這些properties文件,在application.xml加入如下配置
?
?
[plain]?view plain
?copy ?<!--?引入properties配置文件?-->?????<bean?id="propertyConfigurer"?class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">??????<property?name="locations">??????????<list>?????????????<value>classpath:properties/*.properties</value>??????????????<!--要是有多個配置文件,只需在這里繼續(xù)添加即可?-->??????????</list>??????</property>??</bean>?? 3、一些工具類
(1)RedisUtil
上面的bean中,RedisUtil是用來緩存和去除數(shù)據(jù)的實例
?
[java]?view plain
?copy package?com.mucfc.msm.common;????import?java.io.Serializable;??import?java.util.Set;??import?java.util.concurrent.TimeUnit;????import?org.apache.log4j.Logger;??import?org.springframework.data.redis.core.RedisTemplate;??import?org.springframework.data.redis.core.ValueOperations;????public?final?class?RedisUtil?{??????private?Logger?logger?=?Logger.getLogger(RedisUtil.class);?? ????private?RedisTemplate<Serializable,?Object>?redisTemplate;?? ?????? ????public?void?remove(final?String...?keys)?{?? ????????for?(String?key?:?keys)?{?? ????????????remove(key);??????????}??????}???????? ????public?void?removePattern(final?String?pattern)?{?? ????????Set<Serializable>?keys?=?redisTemplate.keys(pattern);??????????if?(keys.size()?>?0)?? ????????????redisTemplate.delete(keys);??????}???????? ????public?void?remove(final?String?key)?{?? ????????if?(exists(key))?{?? ????????????redisTemplate.delete(key);??????????}??????}???????? ????public?boolean?exists(final?String?key)?{?? ????????return?redisTemplate.hasKey(key);?? ????}???????? ????public?Object?get(final?String?key)?{?? ????????Object?result?=?null;?? ????????ValueOperations<Serializable,?Object>?operations?=?redisTemplate??????????????????.opsForValue();??????????result?=?operations.get(key);??????????return?result;?? ????}???????? ????public?boolean?set(final?String?key,?Object?value)?{?? ????????boolean?result?=?false;?? ????????try?{?? ????????????ValueOperations<Serializable,?Object>?operations?=?redisTemplate??????????????????????.opsForValue();??????????????operations.set(key,?value);??????????????result?=?true;?? ????????}?catch?(Exception?e)?{?? ????????????e.printStackTrace();??????????}??????????return?result;?? ????}???????? ????public?boolean?set(final?String?key,?Object?value,?Long?expireTime)?{?? ????????boolean?result?=?false;?? ????????try?{?? ????????????ValueOperations<Serializable,?Object>?operations?=?redisTemplate??????????????????????.opsForValue();??????????????operations.set(key,?value);??????????????redisTemplate.expire(key,?expireTime,?TimeUnit.SECONDS);??????????????result?=?true;?? ????????}?catch?(Exception?e)?{?? ????????????e.printStackTrace();??????????}??????????return?result;?? ????}????????public?void?setRedisTemplate(?? ????????????RedisTemplate<Serializable,?Object>?redisTemplate)?{??????????this.redisTemplate?=?redisTemplate;?? ????}??}?? (2)MethodCacheInterceptor
?
切面MethodCacheInterceptor,這是用來給不同的方法來加入判斷如果緩存存在數(shù)據(jù),從緩存取數(shù)據(jù)。否則第一次從數(shù)據(jù)庫取,并將結(jié)果保存到緩存 中去。
?
[java]?view plain
?copy package?com.mucfc.msm.common;????import?java.io.File;??import?java.io.FileInputStream;??import?java.io.InputStream;??import?java.util.ArrayList;??import?java.util.List;??import?java.util.Properties;????import?org.aopalliance.intercept.MethodInterceptor;??import?org.aopalliance.intercept.MethodInvocation;??import?org.apache.log4j.Logger;??????public?class?MethodCacheInterceptor?implements?MethodInterceptor?{??????private?Logger?logger?=?Logger.getLogger(MethodCacheInterceptor.class);?? ????private?RedisUtil?redisUtil;?? ????private?List<String>?targetNamesList;? ????private?List<String>?methodNamesList;? ????private?Long?defaultCacheExpireTime;? ????private?Long?xxxRecordManagerTime;? ????private?Long?xxxSetRecordManagerTime;? ?????? ????public?MethodCacheInterceptor()?{?? ????????try?{?? ?????????????File?f?=?new?File("D:\\lunaJee-workspace\\msm\\msm_core\\src\\main\\java\\com\\mucfc\\msm\\common\\cacheConf.properties");??? ????????????? ?????????????InputStream?in?=?new?FileInputStream(f);??? ????????????Properties?p?=?new?Properties();?? ????????????p.load(in);?????????????? ????????????String[]?targetNames?=?p.getProperty("targetNames").split(",");?? ????????????String[]?methodNames?=?p.getProperty("methodNames").split(",");?? ?????????????? ????????????defaultCacheExpireTime?=?Long.valueOf(p.getProperty("defaultCacheExpireTime"));?? ????????????xxxRecordManagerTime?=?Long.valueOf(p.getProperty("com.service.impl.xxxRecordManager"));?? ????????????xxxSetRecordManagerTime?=?Long.valueOf(p.getProperty("com.service.impl.xxxSetRecordManager"));?? ???????????? ????????????targetNamesList?=?new?ArrayList<String>(targetNames.length);?? ????????????methodNamesList?=?new?ArrayList<String>(methodNames.length);?? ????????????Integer?maxLen?=?targetNames.length?>?methodNames.length???targetNames.length??????????????????????:?methodNames.length;?????????????? ????????????for?(int?i?=?0;?i?<?maxLen;?i++)?{?? ????????????????if?(i?<?targetNames.length)?{?? ????????????????????targetNamesList.add(targetNames[i]);??????????????????}??????????????????if?(i?<?methodNames.length)?{?? ????????????????????methodNamesList.add(methodNames[i]);??????????????????}??????????????}??????????}?catch?(Exception?e)?{?? ????????????e.printStackTrace();??????????}??????}????????@Override?? ????public?Object?invoke(MethodInvocation?invocation)?throws?Throwable?{?? ????????Object?value?=?null;?? ??????????String?targetName?=?invocation.getThis().getClass().getName();??????????String?methodName?=?invocation.getMethod().getName();?????????? ???????? ????????if?(!isAddCache(targetName,?methodName))?{?? ???????????? ????????????return?invocation.proceed();?? ????????}??????????Object[]?arguments?=?invocation.getArguments();??????????String?key?=?getCacheKey(targetName,?methodName,?arguments);??????????System.out.println(key);????????????try?{?? ???????????? ????????????if?(redisUtil.exists(key))?{?? ????????????????return?redisUtil.get(key);?? ????????????}?????????????? ????????????value?=?invocation.proceed();??????????????if?(value?!=?null)?{?? ????????????????final?String?tkey?=?key;?? ????????????????final?Object?tvalue?=?value;?? ????????????????new?Thread(new?Runnable()?{?? ????????????????????@Override?? ????????????????????public?void?run()?{?? ????????????????????????if?(tkey.startsWith("com.service.impl.xxxRecordManager"))?{?? ????????????????????????????redisUtil.set(tkey,?tvalue,?xxxRecordManagerTime);??????????????????????????}?else?if?(tkey.startsWith("com.service.impl.xxxSetRecordManager"))?{?? ????????????????????????????redisUtil.set(tkey,?tvalue,?xxxSetRecordManagerTime);??????????????????????????}?else?{?? ????????????????????????????redisUtil.set(tkey,?tvalue,?defaultCacheExpireTime);??????????????????????????}??????????????????????}??????????????????}).start();??????????????}??????????}?catch?(Exception?e)?{?? ????????????e.printStackTrace();??????????????if?(value?==?null)?{?? ????????????????return?invocation.proceed();?? ????????????}??????????}??????????return?value;?? ????}???????? ????private?boolean?isAddCache(String?targetName,?String?methodName)?{?? ????????boolean?flag?=?true;?? ????????if?(targetNamesList.contains(targetName)?? ????????????????||?methodNamesList.contains(methodName))?{??????????????flag?=?false;?? ????????}??????????return?flag;?? ????}???????? ????private?String?getCacheKey(String?targetName,?String?methodName,?? ????????????Object[]?arguments)?{??????????StringBuffer?sbu?=?new?StringBuffer();?? ????????sbu.append(targetName).append("_").append(methodName);?? ????????if?((arguments?!=?null)?&&?(arguments.length?!=?0))?{?? ????????????for?(int?i?=?0;?i?<?arguments.length;?i++)?{?? ????????????????sbu.append("_").append(arguments[i]);?? ????????????}??????????}??????????return?sbu.toString();?? ????}????????public?void?setRedisUtil(RedisUtil?redisUtil)?{?? ????????this.redisUtil?=?redisUtil;?? ????}??}?? 4、配置需要緩存的類或方法
?
在application.xml加入如下配置,有多個類或方法可以配置多個
?
[html]?view plain
?copy <bean?id="methodCachePointCut"??class="org.springframework.aop.support.RegexpMethodPointcutAdvisor"?>????????<property?name="advice"?>?? ??????????<ref?local="methodCacheInterceptor"?/>?? ??????</property>?? ??????<property?name="patterns"?>?? ??????????<list>?? ??????????? ?????????????<value>com\.mucfc\.msm\.service\.impl\...*ServiceImpl.*</value?>?? ??????????</list>?? ??????</property>?? </bean?>?? 5、執(zhí)行結(jié)果:
?
寫了一個簡單的單元測試如下:
?
[java]?view plain
?copy @Test??public?void?getSettUnitBySettUnitIdTest()?{??????String?systemId?=?"CES";?? ????String?merchantId?=?"133";?? ????SettUnit?configSettUnit?=?settUnitService.getSettUnitBySettUnitId(systemId,?merchantId,?"ESP");?? ????SettUnit?configSettUnit1?=?settUnitService.getSettUnitBySettUnitId(systemId,?merchantId,?"ESP");?? ????boolean?flag=?(configSettUnit?==?configSettUnit1);?? ????System.out.println(configSettUnit);??????logger.info("查找結(jié)果"?+?configSettUnit.getBusinessType());?? ?????? ? ??????logger.info("查找結(jié)果"?+?string);?? }?? 這是第一次執(zhí)行單元測試的過程:
?
MethodCacheInterceptor這個類中打了斷點,然后每次查詢前都會先進入這個方法
?
?
依次運行,發(fā)現(xiàn)沒有緩存,所以會直接去查數(shù)據(jù)庫
打印了出來的SQL語句:
第二次執(zhí)行:
因為第一次執(zhí)行時,已經(jīng)寫入緩存了。所以第二次直接從緩存中取數(shù)據(jù)
3、取兩次的結(jié)果進行地址的對比:
發(fā)現(xiàn)兩個不是同一個對象,沒錯,是對的。如果是使用ehcache的話,那么二者的內(nèi)存地址會是一樣的。那是因為redis和ehcache使用的緩存機制是不一樣的。ehcache是基于本地電腦的內(nèi)存使用緩存,所以使用緩存取數(shù)據(jù)時直接在本地電腦上取。轉(zhuǎn)換成java對象就會是同一個內(nèi)存地址,而redis它是在裝有redis服務的電腦上(一般是另一臺電腦),所以取數(shù)據(jù)時經(jīng)過傳輸?shù)奖镜?#xff0c;會對應到不同的內(nèi)存地址,所以用==來比較會返回false。但是它確實是從緩存中去取的,這點我們從上面的斷點可以看到。
http://blog.csdn.net/evankaka/article/details/50396325
總結(jié)
以上是生活随笔為你收集整理的Redis整合Spring结合使用缓存实例(转)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。