Spring Boot集成redis做数据缓存

1添加redis支持

在pom.xml中添加

 
  1. <dependency>

  2. <groupId>org.springframework.boot</groupId>

  3. <artifactId>spring-boot-starter-redis</artifactId>

  4. </dependency>

2 redis服务器配置

 
  1. # REDIS (RedisProperties)

  2. # Redis数据库索引(默认为0)

  3. spring.redis.database=0# database name

  4. spring.redis.host=localhost # server host

  5. spring.redis.password= # server password

  6. spring.redis.port=6379 # connection port

  7. # 连接池中的最大空闲连接

  8. spring.redis.pool.max-idle=8 # pool settings ...

  9. # 连接池中的最小空闲连接

  10. spring.redis.pool.min-idle=0

  11. # 连接池最大连接数(使用负值表示没有限制)

  12. spring.redis.pool.max-active=8

  13. # 连接池最大阻塞等待时间(使用负值表示没有限制)

  14. spring.redis.pool.max-wait=-1

  15. spring.redis.sentinel.master= # name of Redis server

  16. spring.redis.sentinel.nodes= # comma-separated list of host:port pairs

3 redis缓存配置文件

 
  1. package com.fcc.config;

  2.  
  3. import com.fasterxml.jackson.annotation.JsonAutoDetect;

  4. import com.fasterxml.jackson.annotation.PropertyAccessor;

  5. import com.fasterxml.jackson.databind.ObjectMapper;

  6. import org.springframework.cache.CacheManager;

  7. import org.springframework.cache.annotation.CachingConfigurerSupport;

  8. import org.springframework.cache.annotation.EnableCaching;

  9. import org.springframework.cache.interceptor.KeyGenerator;

  10. import org.springframework.context.annotation.Bean;

  11. import org.springframework.context.annotation.Configuration;

  12. import org.springframework.data.redis.cache.RedisCacheManager;

  13. import org.springframework.data.redis.connection.RedisConnectionFactory;

  14. import org.springframework.data.redis.core.RedisTemplate;

  15. import org.springframework.data.redis.core.StringRedisTemplate;

  16. import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;

  17.  
  18. import java.lang.reflect.Method;

  19.  
  20. @Configuration

  21. @EnableCaching

  22. public class RedisConfig extends CachingConfigurerSupport {

  23.  
  24. /*定义缓存数据 key 生成策略的bean

  25. 包名+类名+方法名+所有参数

  26. */

  27. @Bean

  28. public KeyGenerator wiselyKeyGenerator(){

  29. return new KeyGenerator() {

  30. @Override

  31. public Object generate(Object target, Method method, Object... params) {

  32. StringBuilder sb = new StringBuilder();

  33. sb.append(target.getClass().getName());

  34. sb.append(method.getName());

  35. for (Object obj : params) {

  36. sb.append(obj.toString());

  37. }

  38. return sb.toString();

  39. }

  40. };

  41.  
  42. }

  43.  
  44. /*要启用spring缓存支持,需创建一个 CacheManager的 bean,CacheManager 接口有很多实现,这里Redis 的集成,用 RedisCacheManager这个实现类

  45. Redis 不是应用的共享内存,它只是一个内存服务器,就像 MySql 似的,

  46. 我们需要将应用连接到它并使用某种“语言”进行交互,因此我们还需要一个连接工厂以及一个 Spring 和 Redis 对话要用的 RedisTemplate,

  47. 这些都是 Redis 缓存所必需的配置,把它们都放在自定义的 CachingConfigurerSupport 中

  48. */

  49. @Bean

  50. public CacheManager cacheManager(

  51. @SuppressWarnings("rawtypes") RedisTemplate redisTemplate) {

  52. RedisCacheManager cacheManager = new RedisCacheManager(redisTemplate);

  53. // cacheManager.setDefaultExpiration(60);//设置缓存保留时间(seconds)

  54. return cacheManager;

  55. }

  56.  
  57. //1.项目启动时此方法先被注册成bean被spring管理

  58. @Bean

  59. public RedisTemplate<String, String> redisTemplate(

  60. RedisConnectionFactory factory) {StringRedisTemplate template = new StringRedisTemplate(factory);

  61. Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);

  62. ObjectMapper om = new ObjectMapper();

  63. om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);

  64. om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);

  65. jackson2JsonRedisSerializer.setObjectMapper(om);

  66. template.setValueSerializer(jackson2JsonRedisSerializer);

  67. template.afterPropertiesSet();

  68. return template;

  69. }

  70. }


 

4 spring提供的@Cacheable、@CachePut、@CacheEvict 注释

 @Cacheable 作用和配置方法

@Cacheable 的作用 主要针对方法配置,能够根据方法的请求参数对其结果进行缓存(缓存的是方法的返回结果)

@Cacheable 主要的参数

value

缓存的名称,在 spring 配置文件中定义,必须指定至少一个

例如:
@Cacheable(value=”mycache”) 或者 
@Cacheable(value={”cache1”,”cache2”}

key

缓存的 key,可以为空,如果指定要按照 SpEL 表达式编写,如果不指定,则缺省按照方法的所有参数进行组合

例如:
@Cacheable(value=”testcache”,key=”#userName”)

condition

缓存的条件,可以为空,使用 SpEL 编写,返回 true 或者 false,只有为 true 才进行缓存

例如:

@Cacheable(value=”testcache”,condition=”#userName.length()>2”)

注意:这里key不写则key的取值默认为参数的组合,且key必须为String类型

缺省key参数:

1.@Cacheable注解的方法参数不为String,则

@Cacheable(value = "role")

    public RolePojo getRole(int id){

        return roleDao.getRole(id);

}

这里key为id(int)报错,java.lang.Integer cannot be cast to java.lang.String

2.@Cacheable注解的方法参数一个且为String,则不报错
RoleService.Java

 
  1. package com.fcc.service;

  2.  
  3. import com.fcc.dao.RoleDao;

  4. import com.fcc.dao.UserDao;

  5. import com.fcc.model.RolePojo;

  6. import com.fcc.model.UserPojo;

  7. import org.springframework.beans.factory.annotation.Autowired;

  8. import org.springframework.cache.annotation.CacheEvict;

  9. import org.springframework.cache.annotation.CachePut;

  10. import org.springframework.cache.annotation.Cacheable;

  11. import org.springframework.stereotype.Service;

  12.  
  13. /**

  14. * @Author:FeiCongcong

  15. * @Date:2017/6/29 0029 14:21

  16. */

  17. @Service

  18. public class RoleService {

  19.  
  20. @Autowired

  21. private RoleDao roleDao;

  22.  
  23. @Cacheable(value = "role")

  24. public RolePojo getRoleByStr(String str){

  25. return roleDao.getRoleByStr(str);

  26. }

  27.  
  28. }

RoleController.java

 
  1. @RequestMapping("/getRoleByStr")

  2. @ResponseBody

  3. public RolePojo getRoleByStr() {

  4. return roleService.getRoleByStr("admin");

  5. }


redis中会存value~keys 这种格式的key,该key下存着以方法入参“admin”为名的数据,“admin”的具体value即为方法返回对象

3.@Cacheable注解的方法参数为多个String

@Cacheable(value = "role")

    public RolePojo getRoleByStr(String str,String str1,String str2){

        return roleDao.getRoleByStr(str);

}

此时报错java.lang.ClassCastException: org.springframework.cache.interceptor.SimpleKey cannot be cast to java.lang.String

故最佳实践:@Cacheable 的key参数不采用缺省

1.在RedisConfig.java中定义缓存数据 key 生成策略的bean,key即采用此bean

 
  1. package com.fcc.config;

  2.  
  3. import com.fasterxml.jackson.annotation.JsonAutoDetect;

  4. import com.fasterxml.jackson.annotation.PropertyAccessor;

  5. import com.fasterxml.jackson.databind.ObjectMapper;

  6. import org.springframework.cache.CacheManager;

  7. import org.springframework.cache.annotation.CachingConfigurerSupport;

  8. import org.springframework.cache.annotation.EnableCaching;

  9. import org.springframework.cache.interceptor.KeyGenerator;

  10. import org.springframework.context.annotation.Bean;

  11. import org.springframework.context.annotation.Configuration;

  12. import org.springframework.data.redis.cache.RedisCacheManager;

  13. import org.springframework.data.redis.connection.RedisConnectionFactory;

  14. import org.springframework.data.redis.core.RedisTemplate;

  15. import org.springframework.data.redis.core.StringRedisTemplate;

  16. import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;

  17.  
  18. import java.lang.reflect.Method;

  19.  
  20. /**

  21. * @Author:FeiCongcong

  22. * @Date:2017/7/3 0003 14:48

  23. */

  24. @Configuration

  25. @EnableCaching

  26. public class RedisConfig extends CachingConfigurerSupport {

  27.  
  28. /*定义缓存数据 key 生成策略的bean

  29. 包名+类名+方法名+所有参数

  30. */

  31. @Bean

  32. public KeyGenerator wiselyKeyGenerator(){

  33. return new KeyGenerator() {

  34. @Override

  35. public Object generate(Object target, Method method, Object... params) {

  36. StringBuilder sb = new StringBuilder();

  37. sb.append(target.getClass().getName());

  38. sb.append(method.getName());

  39. for (Object obj : params) {

  40. sb.append(obj.toString());

  41. }

  42. return sb.toString();

  43. }

  44. };

  45.  
  46. }

  47.  
  48. /*要启用spring缓存支持,需创建一个 CacheManager的 bean,CacheManager 接口有很多实现,这里Redis 的集成,用 RedisCacheManager这个实现类

  49. Redis 不是应用的共享内存,它只是一个内存服务器,就像 MySql 似的,

  50. 我们需要将应用连接到它并使用某种“语言”进行交互,因此我们还需要一个连接工厂以及一个 Spring 和 Redis 对话要用的 RedisTemplate,

  51. 这些都是 Redis 缓存所必需的配置,把它们都放在自定义的 CachingConfigurerSupport 中

  52. */

  53. @Bean

  54. public CacheManager cacheManager(

  55. @SuppressWarnings("rawtypes") RedisTemplate redisTemplate) {

  56. RedisCacheManager cacheManager = new RedisCacheManager(redisTemplate);

  57. // cacheManager.setDefaultExpiration(60);//设置缓存保留时间(seconds)

  58. return cacheManager;

  59. }

  60.  
  61. //1.项目启动时此方法先被注册成bean被spring管理

  62. @Bean

  63. public RedisTemplate<String, String> redisTemplate(

  64. RedisConnectionFactory factory) {StringRedisTemplate template = new StringRedisTemplate(factory);

  65. Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);

  66. ObjectMapper om = new ObjectMapper();

  67. om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);

  68. om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);

  69. jackson2JsonRedisSerializer.setObjectMapper(om);

  70. template.setValueSerializer(jackson2JsonRedisSerializer);

  71. template.afterPropertiesSet();

  72. return template;

  73. }

  74. }

Service层用法:

  @Cacheable(value = "role",keyGenerator="wiselyKeyGenerator")

    public RolePojo getRoleByStrs(String str,String str1,String str2){

        return roleDao.getRoleByStr(str);

}

2.自己组装key(value值+方法参数值)

@Cacheable(value = "role",key="'role'.concat(#id)")

    public RolePojo getRole(int id){

        return roleDao.getRole(id);

}

注:如果key采用单纯的用参数值的组合,

@Cacheable(value = "user",key = "#id.toString()")

    public UserPojo getUser(int id){

        return userDao.getUser(id);

}

@Cacheable(value = "role",key="#id.toString()")

    public RolePojo getRole(int id){

        return roleDao.getRole(id);

}

当调用这两个方法时,若入参相同,就会报错com.fcc.model.RolePojo cannot be cast to com.fcc.model.UserPojo

@CachePut 作用和配置方法

@CachePut 的作用 主要针对方法配置,能够根据方法的请求参数对其结果进行缓存,和 @Cacheable 不同的是,它每次都会触发真实方法的调用

@CachePut 主要的参数

value

缓存的名称,在 spring 配置文件中定义,必须指定至少一个

例如:

@Cacheable(value=”mycache”) 或者

@Cacheable(value={”cache1”,”cache2”}

key

缓存的 key,可以为空,如果指定要按照 SpEL 表达式编写,如果不指定,则缺省按照方法的所有参数进行组合

例如:

@Cacheable(value=”testcache”,key=”#userName”)

condition

缓存的条件,可以为空,使用 SpEL 编写,返回 true 或者 false,只有为 true 才进行缓存

例如:

@Cacheable(value=”testcache”,condition=”#userName.length()>2”)

@CacheEvict 作用和配置方法

@CachEvict 的作用 主要针对方法配置,能够根据一定的条件对缓存进行清空

@CacheEvict 主要的参数

value

缓存的名称,在 spring 配置文件中定义,必须指定至少一个

例如:

@CachEvict(value=”mycache”) 或者

@CachEvict(value={”cache1”,”cache2”}

key

缓存的 key,可以为空,如果指定要按照 SpEL 表达式编写,如果不指定,则缺省按照方法的所有参数进行组合

例如:

@CachEvict(value=”testcache”,key=”#userName”)

condition

缓存的条件,可以为空,使用 SpEL 编写,返回 true 或者 false,只有为 true 才清空缓存

例如:

@CachEvict(value=”testcache”,

condition=”#userName.length()>2”)

allEntries

是否清空所有缓存内容,缺省为 false,如果指定为 true,则方法调用后将立即清空所有缓存

例如:

@CachEvict(value=”testcache”,allEntries=true)

beforeInvocation

是否在方法执行前就清空,缺省为 false,如果指定为 true,则在方法还没有执行的时候就清空缓存,缺省情况下,如果方法执行抛出异常,则不会清空缓存

例如:

@CachEvict(value=”testcache”,beforeInvocation=true)

@Cacheable 相当于insert()操作

@CachePut 相当于update()操作

@CacheEvict 相当于delete()操作

注意事项:

1.要缓存的 Java 对象必须实现 Serializable 接口,因为 Spring 会将对象先序列化再存入 Redis,如果不实现 Serializable 的话将会遇到类似这种错误:nested exception is java.lang.IllegalArgumentException: DefaultSerializer requires a Serializable payload but received an object of type [......]]

2.CacheManager 设置缓存过期时间,否则缓存对象将永不过期,这样做可以避免一些野数据“永久保存”。此外,设置缓存过期时间也有助于资源利用最大化,因为缓存里保留的永远是热点数据。

(1).在cacheManager里面配置,对所有@Cache注解起作用

代码如下:

@Bean

    public CacheManager cacheManager(

            @SuppressWarnings("rawtypes") RedisTemplate redisTemplate) {

        RedisCacheManager cacheManager = new RedisCacheManager(redisTemplate);

        cacheManager.setDefaultExpiration(60);//设置缓存保留时间(seconds)

        return cacheManager;

}

源码跟踪分析:

跟踪@Cacheable调用时发现@Cacheable 的实现是通过cglib代理来实现:

1.CglibAopProxy.intercept的方法,该方法中通过

List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);

获取一个List拦截链,然后通过

retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();

方法执行对应的拦截链进行执行处理。

最后通过,

processReturnType(proxy, target, method, retVal);

处理返回值,并返回。 其中具体在AbstractCacheInvoker.doPut()方法执行时,将数据插入到redis服务器

参考文档:http://blog.csdn.net/mergades/article/details/45244453

http://www.cnblogs.com/softidea/p/5801499.html

http://blog.csdn.net/sanjay_f/article/details/47372967

猜你喜欢

转载自blog.csdn.net/qq_29663071/article/details/81393661