Redis整合Spring结合使用缓存实例(转)

         林炳文Evankaka原创作品。转载请注明出处http://blog.csdn.net/evankaka

         摘要:本文介绍了如何在Spring中配置redis,并通过Spring中AOP的思想,将缓存的方法切入到有需要进入缓存的类或方法前面。

一、Redis介绍

什么是Redis?

      redis是一个key-value存储系统。和Memcached类似,它支持存储的value类型相对更多,包括string(字符串)、list(链表)、set(集合)、zset(sorted set --有序集合)和hash(哈希类型)。这些数据类型都支持push/pop、add/remove及取交集并集和差集及更丰富的操作,而且这些操作都是原子性的。在此基础上,redis支持各种不同方式的排序。与memcached一样,为了保证效率,数据都是缓存在内存中。区别的是redis会周期性的把更新的数据写入磁盘或者把修改操作写入追加的记录文件,并且在此基础上实现了master-slave(主从)同步。

它有什么特点?

(1)Redis数据库完全在内存中,使用磁盘仅用于持久性。
(2)相比许多键值数据存储,Redis拥有一套较为丰富的数据类型。
(3)Redis可以将数据复制到任意数量的从服务器。

Redis 优势?
 (1)异常快速:Redis的速度非常快,每秒能执行约11万集合,每秒约81000+条记录。
 (2)支持丰富的数据类型:Redis支持最大多数开发人员已经知道像列表,集合,有序集合,散列数据类型。这使得它非常容易解决各种各样的问题,因为我们知道哪些问题是可以处理通过它的数据类型更好。
(3)操作都是原子性:所有Redis操作是原子的,这保证了如果两个客户端同时访问的Redis服务器将获得更新后的值。
(4)多功能实用工具:Redis是一个多实用的工具,可以在多个用例如缓存,消息,队列使用(Redis原生支持发布/订阅),任何短暂的数据,应用程序,如Web应用程序会话,网页命中计数等。

Redis 缺点?

(1)单线程

(2)耗内存

二、使用实例

本文使用maven+eclipse+sping

1、引入jar包

 

[html] view plain copy

 

  1.     <!--Redis start -->  
  2. <dependency>  
  3.     <groupId>org.springframework.data</groupId>  
  4.     <artifactId>spring-data-redis</artifactId>  
  5.     <version>1.6.1.RELEASE</version>  
  6. </dependency>  
  7. <dependency>  
  8.     <groupId>redis.clients</groupId>  
  9.     <artifactId>jedis</artifactId>  
  10.     <version>2.7.3</version>  
  11. </dependency>  
  12.    <!--Redis end -->  

2、配置bean

 

在application.xml加入如下配置

 

[html] view plain copy

 

  1. <!-- jedis 配置 -->  
  2.    <bean id="poolConfig" class="redis.clients.jedis.JedisPoolConfig" >  
  3.          <property name="maxIdle" value="${redis.maxIdle}" />  
  4.          <property name="maxWaitMillis" value="${redis.maxWait}" />  
  5.          <property name="testOnBorrow" value="${redis.testOnBorrow}" />  
  6.    </bean >  
  7.   <!-- redis服务器中心 -->  
  8.    <bean id="connectionFactory"  class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory" >  
  9.          <property name="poolConfig" ref="poolConfig" />  
  10.          <property name="port" value="${redis.port}" />  
  11.          <property name="hostName" value="${redis.host}" />  
  12.          <property name="password" value="${redis.password}" />  
  13.          <property name="timeout" value="${redis.timeout}" ></property>  
  14.    </bean >  
  15.    <bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate" >  
  16.          <property name="connectionFactory" ref="connectionFactory" />  
  17.          <property name="keySerializer" >  
  18.              <bean class="org.springframework.data.redis.serializer.StringRedisSerializer" />  
  19.          </property>  
  20.          <property name="valueSerializer" >  
  21.              <bean class="org.springframework.data.redis.serializer.JdkSerializationRedisSerializer" />  
  22.          </property>  
  23.    </bean >  
  24.      
  25.     <!-- cache配置 -->  
  26.    <bean id="methodCacheInterceptor" class="com.mucfc.msm.common.MethodCacheInterceptor" >  
  27.          <property name="redisUtil" ref="redisUtil" />  
  28.    </bean >  
  29.    <bean id="redisUtil" class="com.mucfc.msm.common.RedisUtil" >  
  30.          <property name="redisTemplate" ref="redisTemplate" />  
  31.    </bean >  

其中配置文件redis一些配置数据redis.properties如下:

 

 

[plain] view plain copy

 

  1. #redis中心  
  2. redis.host=10.75.202.11  
  3. redis.port=6379  
  4. redis.password=123456  
  5. redis.maxIdle=100  
  6. redis.maxActive=300  
  7. redis.maxWait=1000  
  8. redis.testOnBorrow=true  
  9. redis.timeout=100000  
  10.   
  11. # 不需要加入缓存的类  
  12. targetNames=xxxRecordManager,xxxSetRecordManager,xxxStatisticsIdentificationManager  
  13. # 不需要缓存的方法  
  14. methodNames=  
  15.   
  16. #设置缓存失效时间  
  17. com.service.impl.xxxRecordManager= 60  
  18. com.service.impl.xxxSetRecordManager= 60  
  19. defaultCacheExpireTime=3600  
  20.   
  21. fep.local.cache.capacity =10000  

要扫这些properties文件,在application.xml加入如下配置

 

 

[plain] view plain copy

 

  1.  <!-- 引入properties配置文件 -->    
  2.  <bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">  
  3.     <property name="locations">  
  4.         <list>  
  5.            <value>classpath:properties/*.properties</value>  
  6.             <!--要是有多个配置文件,只需在这里继续添加即可 -->  
  7.         </list>  
  8.     </property>  
  9. </bean>  

3、一些工具类

(1)RedisUtil

上面的bean中,RedisUtil是用来缓存和去除数据的实例

 

[java] view plain copy

 

  1. package com.mucfc.msm.common;  
  2.   
  3. import java.io.Serializable;  
  4. import java.util.Set;  
  5. import java.util.concurrent.TimeUnit;  
  6.   
  7. import org.apache.log4j.Logger;  
  8. import org.springframework.data.redis.core.RedisTemplate;  
  9. import org.springframework.data.redis.core.ValueOperations;  
  10.   
  11. /** 
  12.  * redis cache 工具类 
  13.  *  
  14.  */  
  15. public final class RedisUtil {  
  16.     private Logger logger = Logger.getLogger(RedisUtil.class);  
  17.     private RedisTemplate<Serializable, Object> redisTemplate;  
  18.   
  19.     /** 
  20.      * 批量删除对应的value 
  21.      *  
  22.      * @param keys 
  23.      */  
  24.     public void remove(final String... keys) {  
  25.         for (String key : keys) {  
  26.             remove(key);  
  27.         }  
  28.     }  
  29.   
  30.     /** 
  31.      * 批量删除key 
  32.      *  
  33.      * @param pattern 
  34.      */  
  35.     public void removePattern(final String pattern) {  
  36.         Set<Serializable> keys = redisTemplate.keys(pattern);  
  37.         if (keys.size() > 0)  
  38.             redisTemplate.delete(keys);  
  39.     }  
  40.   
  41.     /** 
  42.      * 删除对应的value 
  43.      *  
  44.      * @param key 
  45.      */  
  46.     public void remove(final String key) {  
  47.         if (exists(key)) {  
  48.             redisTemplate.delete(key);  
  49.         }  
  50.     }  
  51.   
  52.     /** 
  53.      * 判断缓存中是否有对应的value 
  54.      *  
  55.      * @param key 
  56.      * @return 
  57.      */  
  58.     public boolean exists(final String key) {  
  59.         return redisTemplate.hasKey(key);  
  60.     }  
  61.   
  62.     /** 
  63.      * 读取缓存 
  64.      *  
  65.      * @param key 
  66.      * @return 
  67.      */  
  68.     public Object get(final String key) {  
  69.         Object result = null;  
  70.         ValueOperations<Serializable, Object> operations = redisTemplate  
  71.                 .opsForValue();  
  72.         result = operations.get(key);  
  73.         return result;  
  74.     }  
  75.   
  76.     /** 
  77.      * 写入缓存 
  78.      *  
  79.      * @param key 
  80.      * @param value 
  81.      * @return 
  82.      */  
  83.     public boolean set(final String key, Object value) {  
  84.         boolean result = false;  
  85.         try {  
  86.             ValueOperations<Serializable, Object> operations = redisTemplate  
  87.                     .opsForValue();  
  88.             operations.set(key, value);  
  89.             result = true;  
  90.         } catch (Exception e) {  
  91.             e.printStackTrace();  
  92.         }  
  93.         return result;  
  94.     }  
  95.   
  96.     /** 
  97.      * 写入缓存 
  98.      *  
  99.      * @param key 
  100.      * @param value 
  101.      * @return 
  102.      */  
  103.     public boolean set(final String key, Object value, Long expireTime) {  
  104.         boolean result = false;  
  105.         try {  
  106.             ValueOperations<Serializable, Object> operations = redisTemplate  
  107.                     .opsForValue();  
  108.             operations.set(key, value);  
  109.             redisTemplate.expire(key, expireTime, TimeUnit.SECONDS);  
  110.             result = true;  
  111.         } catch (Exception e) {  
  112.             e.printStackTrace();  
  113.         }  
  114.         return result;  
  115.     }  
  116.   
  117.     public void setRedisTemplate(  
  118.             RedisTemplate<Serializable, Object> redisTemplate) {  
  119.         this.redisTemplate = redisTemplate;  
  120.     }  
  121. }  

(2)MethodCacheInterceptor

 

切面MethodCacheInterceptor,这是用来给不同的方法来加入判断如果缓存存在数据,从缓存取数据。否则第一次从数据库取,并将结果保存到缓存 中去。

 

[java] view plain copy

 

  1. package com.mucfc.msm.common;  
  2.   
  3. import java.io.File;  
  4. import java.io.FileInputStream;  
  5. import java.io.InputStream;  
  6. import java.util.ArrayList;  
  7. import java.util.List;  
  8. import java.util.Properties;  
  9.   
  10. import org.aopalliance.intercept.MethodInterceptor;  
  11. import org.aopalliance.intercept.MethodInvocation;  
  12. import org.apache.log4j.Logger;  
  13.   
  14.   
  15. public class MethodCacheInterceptor implements MethodInterceptor {  
  16.     private Logger logger = Logger.getLogger(MethodCacheInterceptor.class);  
  17.     private RedisUtil redisUtil;  
  18.     private List<String> targetNamesList; // 不加入缓存的service名称  
  19.     private List<String> methodNamesList; // 不加入缓存的方法名称  
  20.     private Long defaultCacheExpireTime; // 缓存默认的过期时间  
  21.     private Long xxxRecordManagerTime; //  
  22.     private Long xxxSetRecordManagerTime; //  
  23.   
  24.     /** 
  25.      * 初始化读取不需要加入缓存的类名和方法名称 
  26.      */  
  27.     public MethodCacheInterceptor() {  
  28.         try {  
  29.              File f = new File("D:\\lunaJee-workspace\\msm\\msm_core\\src\\main\\java\\com\\mucfc\\msm\\common\\cacheConf.properties");   
  30.              //配置文件位置直接被写死,有需要自己修改下  
  31.              InputStream in = new FileInputStream(f);   
  32. //          InputStream in = getClass().getClassLoader().getResourceAsStream(  
  33. //                  "D:\\lunaJee-workspace\\msm\\msm_core\\src\\main\\java\\com\\mucfc\\msm\\common\\cacheConf.properties");  
  34.             Properties p = new Properties();  
  35.             p.load(in);  
  36.             // 分割字符串  
  37.             String[] targetNames = p.getProperty("targetNames").split(",");  
  38.             String[] methodNames = p.getProperty("methodNames").split(",");  
  39.   
  40.             // 加载过期时间设置  
  41.             defaultCacheExpireTime = Long.valueOf(p.getProperty("defaultCacheExpireTime"));  
  42.             xxxRecordManagerTime = Long.valueOf(p.getProperty("com.service.impl.xxxRecordManager"));  
  43.             xxxSetRecordManagerTime = Long.valueOf(p.getProperty("com.service.impl.xxxSetRecordManager"));  
  44.             // 创建list  
  45.             targetNamesList = new ArrayList<String>(targetNames.length);  
  46.             methodNamesList = new ArrayList<String>(methodNames.length);  
  47.             Integer maxLen = targetNames.length > methodNames.length ? targetNames.length  
  48.                     : methodNames.length;  
  49.             // 将不需要缓存的类名和方法名添加到list中  
  50.             for (int i = 0; i < maxLen; i++) {  
  51.                 if (i < targetNames.length) {  
  52.                     targetNamesList.add(targetNames[i]);  
  53.                 }  
  54.                 if (i < methodNames.length) {  
  55.                     methodNamesList.add(methodNames[i]);  
  56.                 }  
  57.             }  
  58.         } catch (Exception e) {  
  59.             e.printStackTrace();  
  60.         }  
  61.     }  
  62.   
  63.     @Override  
  64.     public Object invoke(MethodInvocation invocation) throws Throwable {  
  65.         Object value = null;  
  66.   
  67.         String targetName = invocation.getThis().getClass().getName();  
  68.         String methodName = invocation.getMethod().getName();  
  69.         // 不需要缓存的内容  
  70.         //if (!isAddCache(StringUtil.subStrForLastDot(targetName), methodName)) {  
  71.         if (!isAddCache(targetName, methodName)) {  
  72.             // 执行方法返回结果  
  73.             return invocation.proceed();  
  74.         }  
  75.         Object[] arguments = invocation.getArguments();  
  76.         String key = getCacheKey(targetName, methodName, arguments);  
  77.         System.out.println(key);  
  78.   
  79.         try {  
  80.             // 判断是否有缓存  
  81.             if (redisUtil.exists(key)) {  
  82.                 return redisUtil.get(key);  
  83.             }  
  84.             // 写入缓存  
  85.             value = invocation.proceed();  
  86.             if (value != null) {  
  87.                 final String tkey = key;  
  88.                 final Object tvalue = value;  
  89.                 new Thread(new Runnable() {  
  90.                     @Override  
  91.                     public void run() {  
  92.                         if (tkey.startsWith("com.service.impl.xxxRecordManager")) {  
  93.                             redisUtil.set(tkey, tvalue, xxxRecordManagerTime);  
  94.                         } else if (tkey.startsWith("com.service.impl.xxxSetRecordManager")) {  
  95.                             redisUtil.set(tkey, tvalue, xxxSetRecordManagerTime);  
  96.                         } else {  
  97.                             redisUtil.set(tkey, tvalue, defaultCacheExpireTime);  
  98.                         }  
  99.                     }  
  100.                 }).start();  
  101.             }  
  102.         } catch (Exception e) {  
  103.             e.printStackTrace();  
  104.             if (value == null) {  
  105.                 return invocation.proceed();  
  106.             }  
  107.         }  
  108.         return value;  
  109.     }  
  110.   
  111.     /** 
  112.      * 是否加入缓存 
  113.      *  
  114.      * @return 
  115.      */  
  116.     private boolean isAddCache(String targetName, String methodName) {  
  117.         boolean flag = true;  
  118.         if (targetNamesList.contains(targetName)  
  119.                 || methodNamesList.contains(methodName)) {  
  120.             flag = false;  
  121.         }  
  122.         return flag;  
  123.     }  
  124.   
  125.     /** 
  126.      * 创建缓存key 
  127.      * 
  128.      * @param targetName 
  129.      * @param methodName 
  130.      * @param arguments 
  131.      */  
  132.     private String getCacheKey(String targetName, String methodName,  
  133.             Object[] arguments) {  
  134.         StringBuffer sbu = new StringBuffer();  
  135.         sbu.append(targetName).append("_").append(methodName);  
  136.         if ((arguments != null) && (arguments.length != 0)) {  
  137.             for (int i = 0; i < arguments.length; i++) {  
  138.                 sbu.append("_").append(arguments[i]);  
  139.             }  
  140.         }  
  141.         return sbu.toString();  
  142.     }  
  143.   
  144.     public void setRedisUtil(RedisUtil redisUtil) {  
  145.         this.redisUtil = redisUtil;  
  146.     }  
  147. }  

4、配置需要缓存的类或方法

 

在application.xml加入如下配置,有多个类或方法可以配置多个

 

[html] view plain copy

 

  1. <!-- 需要加入缓存的类或方法 -->  
  2. <bean id="methodCachePointCut"  class="org.springframework.aop.support.RegexpMethodPointcutAdvisor" >  
  3.       <property name="advice" >  
  4.           <ref local="methodCacheInterceptor" />  
  5.       </property>  
  6.       <property name="patterns" >  
  7.           <list>  
  8.            <!-- 确定正则表达式列表 -->  
  9.              <value>com\.mucfc\.msm\.service\.impl\...*ServiceImpl.*</value >  
  10.           </list>  
  11.       </property>  
  12. </bean >  

5、执行结果:

 

写了一个简单的单元测试如下:

 

[java] view plain copy

 

  1. @Test  
  2. public void getSettUnitBySettUnitIdTest() {  
  3.     String systemId = "CES";  
  4.     String merchantId = "133";  
  5.     SettUnit configSettUnit = settUnitService.getSettUnitBySettUnitId(systemId, merchantId, "ESP");  
  6.     SettUnit configSettUnit1 = settUnitService.getSettUnitBySettUnitId(systemId, merchantId, "ESP");  
  7.     boolean flag= (configSettUnit == configSettUnit1);  
  8.     System.out.println(configSettUnit);  
  9.     logger.info("查找结果" + configSettUnit.getBusinessType());  
  10.     
  11.   //  localSecondFIFOCache.put("configSettUnit", configSettUnit.getBusinessType());  
  12.  //  String string = localSecondFIFOCache.get("configSettUnit");  
  13.       logger.info("查找结果" + string);  
  14. }  

这是第一次执行单元测试的过程:

 

MethodCacheInterceptor这个类中打了断点,然后每次查询前都会先进入这个方法

 

 

依次运行,发现没有缓存,所以会直接去查数据库

打印了出来的SQL语句:

第二次执行:

因为第一次执行时,已经写入缓存了。所以第二次直接从缓存中取数据

3、取两次的结果进行地址的对比:

发现两个不是同一个对象,没错,是对的。如果是使用ehcache的话,那么二者的内存地址会是一样的。那是因为redis和ehcache使用的缓存机制是不一样的。ehcache是基于本地电脑的内存使用缓存,所以使用缓存取数据时直接在本地电脑上取。转换成java对象就会是同一个内存地址,而redis它是在装有redis服务的电脑上(一般是另一台电脑),所以取数据时经过传输到本地,会对应到不同的内存地址,所以用==来比较会返回false。但是它确实是从缓存中去取的,这点我们从上面的断点可以看到。

http://blog.csdn.net/evankaka/article/details/50396325

时间: 2024-09-13 10:10:39

Redis整合Spring结合使用缓存实例(转)的相关文章

Redis整合Spring结合使用缓存实例_Redis

一.Redis介绍什么是Redis?      redis是一个key-value存储系统.和Memcached类似,它支持存储的value类型相对更多,包括string(字符串).list(链表).set(集合).zset(sorted set --有序集合)和hash(哈希类型).这些数据类型都支持push/pop.add/remove及取交集并集和差集及更丰富的操作,而且这些操作都是原子性的.在此基础上,redis支持各种不同方式的排序.与memcached一样,为了保证效率,数据都是缓存

Redis整合Spring结合使用缓存实例

一.Redis介绍 什么是Redis? redis是一个key-value存储系统.和Memcached类似,它支持存储的value类型相对更多,包括string(字符串). list(链表).set(集合).zset(sorted set –有序集合)和hash(哈希类型).这些数据类型都支持push/pop.add/remove及取交集并集和差集及更丰富的操作,而且这些操作都是原 子性的.在此基础上,redis支持各种不同方式的排序.与memcached一样,为了保证效率,数据都是缓存在内存

Redis 整合spring ,做mysql的缓存

项目环境: 在SpringMVC + MyBatis + Mysql.Redis部署在Linux虚拟机. 1.整体思路 参考Ehcache实现MyBatis二级缓存代码(Maven引用对应jar查阅) 使用Spring管理Redis连接池 模仿EhcacheCache,实现RedisCache 2.pom.xml中加入Maven <!-- spring-redis实现 --> <dependency> <groupId>org.springframework.data&

Hibernate整合spring配置二级缓存

applicationContext.xml 文件配置: <prop key="hibernate.cache.use_second_level_cache">true</prop> <!--设置缓存机制为二级缓存 --> <prop key="hibernate.cache.use_query_cache">true</prop> <!--启动查询缓存 --> <prop key=&qu

Echache整合Spring缓存实例讲解(转)

           林炳文Evankaka原创作品.转载请注明出处http://blog.csdn.net/evankaka              摘要:本文主要介绍了EhCache,并通过整合Spring给出了一个使用实例. 一.EhCache 介绍           EhCache 是一个纯Java的进程内缓存框架,具有快速.精干等特点,是Hibernate中默认的CacheProvider.Ehcache是一种广泛使用的开源Java分布式缓存.主要面向通用缓存,Java EE和轻量

授权-求OpenID整合spring security oauth2 实例

问题描述 求OpenID整合spring security oauth2 实例 客户端利用openID作身份验证,然后绑定Oauth授权服务器,获取资源

Ehcache 整合Spring 使用页面、对象缓存(转)

Ehcache在很多项目中都出现过,用法也比较简单.一般的加些配置就可以了,而且Ehcache可以对页面.对象.数据进行缓存,同时支持集群/分布式缓存.如果整合Spring.Hibernate也非常的简单,Spring对Ehcache的支持也非常好.EHCache支持内存和磁盘的缓存,支持LRU.LFU和FIFO多种淘汰算法,支持分布式的Cache,可以作为Hibernate的缓存插件.同时它也能提供基于Filter的Cache,该Filter可以缓存响应的内容并采用Gzip压缩提高响应速度.

Redis和Spring的整合

因为经常用到几个工具类,因此备份一下,后续可以直接copy过去 spring配置 <bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig"> <property name="maxIdle" value="${redis.pool.maxIdle}" /> <!-- 最大能够保持idel状态的对象数 -->

Ehcache 整合Spring 使用页面、对象缓存

Ehcache在很多项目中都出现过,用法也比较简单.一般的加些配置就可以了,而且Ehcache可以对页面.对象. 数据进行缓存,同时支持集群/分布式缓存.如果整合Spring.Hibernate也非常的简单,Spring对Ehcache的支持也非常好. EHCache支持内存和磁盘的缓存,支持LRU.LFU和FIFO多种淘汰算法,支持分布式的Cache,可以作为Hibernate的缓存插件.同时 它也能提供基于Filter的Cache,该Filter可以缓存响应的内容并采用Gzip压缩提高响应速