Springboot整合SpringCache+Redis

springcache是java的缓存框架,它是一种抽象,一种规范,开发者不能直接使用他,必须用他的一些实现,比如redis,ehcache。两个的关系就好比jdbc与mysql驱动的关系。springboot为搜springcache提供了自动化配置方案,只需要引入依赖即可。
Cache接口下Spring提供了各种xxxCache的实现,如RedisCache,EhCacheCache ,ConcurrentMapCache等;

一、Cache与CacheManger

针对不同的缓存技术,需要实现不同的cacheManager,Spring定义了如下的cacheManger实现。
在这里插入图片描述
常规的SpringBoot已经为我们自动配置了EhCache、Collection、Guava、ConcurrentMap等缓存,默认使用ConcurrentMapCacheManager。SpringBoot的application.properties配置文件,使用spring.cache前缀的属性进行配置。

2、缓存依赖

spring-boot-starter-cache 为基础依赖,其他依赖根据使用不同的缓存技术选择加入,默认情况下使用 ConcurrentMapCache不需要引用任何依赖,这里使用 RedisCacheManager,则只需要引入redis的"spring-boot-starter-data-redis"依赖即可,Redis使用模式使用pool2连接池,再需要引用org.apache.commons的依赖"commons-pool2"

<!--spring cache,当使用的是redis最为缓存,则该依赖页不需要-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<!--redis 连接池依赖包-->
<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-pool2</artifactId>
</dependency>
<!--redis -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

3、application.yml配置

spring:
  application:
    name: cache_demo
  datasource:
    druid:
      driver-class-name: com.mysql.cj.jdbc.Driver
      url: jdbc:mysql://ip:3306/itcast?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&useSSL=false&allowPublicKeyRetrieval=true
      username: root
      password: 123456
      type: com.alibaba.druid.pool.DruidDataSource
  redis:
    database: 0         # Redis数据库索引(默认为0)
    timeout: 60000      # 连接超时时间(毫秒)
    password: 123456
    host: ip
    port: 6379
    lettuce:
      shutdown-timeout: 100    # 毫秒
      pool:
        min-idle: 5    # 连接池中的最小空闲连接
        max-active: 5000  # 连接池最大连接数(使用负值表示没有限制)
        max-idle: 10  # 连接池中的最大空闲连接
        max-wait: 1000   # 连接池最大阻塞等待时间(使用负值表示没有限制):毫秒
  cache:
    redis:
      time-to-live: 1800000     # 缓存默认有效时长,以毫秒为单位
    type: redis    #指定使用redis作为缓存

4、缓存注解

下面是缓存公用接口注释,使用与任何缓存技术

  • 1,@EnableCaching:在启动类注解@EnableCaching开启缓存
@SpringBootApplication
@EnableCaching  //开启缓存
public class DemoApplication{

    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }
    
}
  • 2、@Cacheable
    配置了getById函数的返回值将被加入缓存。同时在查询时,会先从缓存中获取,若不存在才会执行方法。

该注解主要有下面几个参数:

  • value、cacheNames:两个等同的参数(cacheNames为Spring 4新增,作为value的别名),用于指定缓存存储的集合名。由于Spring 4中新增了@CacheConfig,因此在Spring 3中原本必须有的value属性,也成为非必需项了
  • key:缓存对象存储在Map集合中的key值,非必需,缺省按照函数的所有参数组合作为key值,若自己配置需使用SpEL表达式,比如:@Cacheable(key = “#p0”):使用函数第一个参数作为缓存的key值
  • condition:缓存对象的条件,非必需,也需使用SpEL表达式,只有满足表达式条件的内容才会被缓存,比如:@Cacheable(key = “#p0”, condition = “#p0.length() < 3”),表示只有当第一个参数的长度小于3的时候才会被缓存
  • unless:另外一个缓存条件参数,非必需,需使用SpEL表达式。它不同于condition参数的地方在于它的判断时机,该条件是在函数被调用之后才做判断的,所以它可以通过对result进行判断。
  • keyGenerator:用于指定key生成器,非必需。若需要指定一个自定义的key生成器,我们需要去实现org.springframework.cache.interceptor.KeyGenerator接口,并使用该参数来指定。需要注意的是:该参数与key是互斥的
  • cacheManager:用于指定使用哪个缓存管理器,非必需。只有当有多个时才需要使用
  • cacheResolver:用于指定使用那个缓存解析器,非必需。需通过org.springframework.cache.interceptor.CacheResolver接口来实现自己的缓存解析器,并用该参数指定。
@RestController
@RequestMapping("/user")
@Slf4j
public class UserController {
    @Autowired
    private UserService userService;
        /**
     * Cacheable:触发缓存填充的操作,检查缓存是否存在,存在则取缓存数据,直接返回,不存在则查数据库写入缓存
     * value:缓存的名称,每个缓存名称下可以有多个key
     * key:缓存的key
     * condition:设置缓存的判断条件,当返回值不为 null 时才存缓存
     * unless:与condition相反,满足条件则不缓存
     * @param id
     * @return
     */
    @Cacheable(value = "userCache", key = "#id", unless = "#result == null")
    @GetMapping("/{id}")
    public User getById(@PathVariable Long id){
        User user = userService.getById(id);
        return user;
    }
}
  • 3、@CachePut
    主要针对方法配置,能够根据方法的请求参数对其结果进行缓存,和 @Cacheable 不同的是,它每次都会触发真实方法的调用 。简单来说就是用户更新缓存数据。但需要注意的是该注解的value 和 key 必须与要更新的缓存相同,也就是与@Cacheable 相同。示例:
@RestController
@RequestMapping("/user")
@Slf4j
public class UserController {
    @Autowired
    private UserService userService;
    
    /**
     * CachePut将方法返回值放入缓存
     * value:缓存的名称,每个缓存名称下可以有多个key
     * key:缓存的key
     * @param user
     * @return
     */
    @CachePut(value = "userCache", key = "#result.id")
    @PostMapping
    public User save(@RequestBody User user){
        userService.save(user);
        return user;
    }
}
  • 4、@CacheEvict
    配置于函数上,通常用在删除方法上,用来从缓存中移除相应数据。除了同@Cacheable一样的参数之外,它还有下面两个参数:
    allEntries:非必需,默认为false。当为true时,会移除所有数据。如:@CachEvict(value=”testcache”,allEntries=true)
    beforeInvocation:非必需,默认为false,会在调用方法之后移除数据。当为true时,会在调用方法之前移除数据。 如:@CachEvict(value=”testcache”,beforeInvocation=true)
@RestController
@RequestMapping("/user")
@Slf4j
public class UserController {
    @Autowired
    private UserService userService;
    
    /**
     * CacheEvict:清理指定缓存
     * value:缓存的名称,每个缓存名称下可以有多个key
     * key:缓存的key
     * @param id
     */
    @CacheEvict(value = "userCache", key = "#id")
    //@CacheEvict(value = "userCache", key = "#p0")
    //@CacheEvict(value = "userCache", key = "#root.args[0]")
    @DeleteMapping("/{id}")
    public void delete(@PathVariable Long id){
        userService.removeById(id);
    }
}
  • 5、@CacheConfig
    统一配置本类的缓存注解的属性,在类上面统一定义缓存的名字,方法上面就不用标注了,当标记在一个类上时则表示该类所有的方法都是支持缓存的
@RestController
@RequestMapping("/user")
@Slf4j
@CacheConfig(cacheNames = {"userCache"})
public class UserController {
    @Autowired
    private UserService userService;
    
    /**
     * CacheEvict:清理指定缓存
     * value:缓存的名称,每个缓存名称下可以有多个key
     * key:缓存的key
     * @param id
     */
    @CacheEvict(key = "#id")
    //@CacheEvict(value = "userCache", key = "#p0")
    //@CacheEvict(value = "userCache", key = "#root.args[0]")
    @DeleteMapping("/{id}")
    public void delete(@PathVariable Long id){
        userService.removeById(id);
    }
}

5、SpEL上下文数据

Spring Cache提供了一些供我们使用的SpEL上下文数据,下表直接摘自Spring官方文档:
在这里插入图片描述
注意:

1.当我们要使用root对象的属性作为key时我们也可以将“#root”省略,因为Spring默认使用的就是root对象的属性。 如
@Cacheable(key = "targetClass + methodName +#p0")

2、使用方法参数时我们可以直接使用“#参数名”或者“#p参数index”。 如:

@Cacheable(value="users", key="#id")

@Cacheable(value="users", key="#p0")

3、SpEL提供了多种运算符
在这里插入图片描述

6、自定义序列化

测试过程中发现写入缓存的数据为乱码,可以通过自定义装配来
在这里插入图片描述

  1. 装配序列化类型
@Bean
public RedisTemplate<String, Object> redisTemplate(LettuceConnectionFactory connectionFactory) {
    // 配置redisTemplate
    RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
    redisTemplate.setConnectionFactory(connectionFactory);
    redisTemplate.setKeySerializer(new StringRedisSerializer());//key序列化
    redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer());//value序列化
    redisTemplate.afterPropertiesSet();
    return redisTemplate;
}
  1. 装配过期时间
/**
* 通过RedisCacheManager配置过期时间
*
* @param redisConnectionFactory
* @return
*/
@Bean
public RedisCacheManager cacheManager(RedisConnectionFactory redisConnectionFactory) {
   RedisCacheConfiguration redisCacheConfiguration = RedisCacheConfiguration.defaultCacheConfig()
           .entryTtl(Duration.ofHours(1)); // 设置缓存有效期一小时
   return RedisCacheManager
           .builder(RedisCacheWriter.nonLockingRedisCacheWriter(redisConnectionFactory))
           .cacheDefaults(redisCacheConfiguration).build();
}
  1. 一个比较完整的装配类 demo
/**
 * 自定义缓存配置文件,继承 CachingConfigurerSupport
 * Created by huanl on 2017/8/22.
 */
@Configuration
@EnableCaching
public class RedisConfig extends CachingConfigurerSupport{
    public RedisConfig() {
        super();
    }

    /**
     * 指定使用哪一种缓存
     * @param redisTemplate
     * @return
     */
    @Bean
    public CacheManager cacheManager(RedisTemplate<?,?> redisTemplate) {
        RedisCacheManager rcm = new RedisCacheManager(redisTemplate);
        return rcm;
    }

    /**
     * 指定默认的key生成方式
     * @return
     */
    @Override
    public KeyGenerator keyGenerator() {
       KeyGenerator keyGenerator = new KeyGenerator() {
           @Override
           public Object generate(Object o, Method method, Object... objects) {
               StringBuilder sb = new StringBuilder();
               sb.append(o.getClass().getName());
               sb.append(method.getName());
               for (Object obj : objects) {
                   sb.append(obj.toString());
               }
               return sb.toString();
           }
       };
       return keyGenerator;
    }

    @Override
    public CacheResolver cacheResolver() {
        return super.cacheResolver();
    }

    @Override
    public CacheErrorHandler errorHandler() {
        return super.errorHandler();
    }

    /**
     * redis 序列化策略 ,通常情况下key值采用String序列化策略
     * StringRedisTemplate默认采用的是String的序列化策略,保存的key和value都是采用此策略序列化保存的。StringRedisSerializer
     * RedisTemplate默认采用的是JDK的序列化策略,保存的key和value都是采用此策略序列化保存的。JdkSerializationRedisSerializer
     * @param factory
     * @return
     */
    @Bean
    public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory factory){
        RedisTemplate<Object, Object> redisTemplate = new RedisTemplate<>();
        redisTemplate.setConnectionFactory(factory);

//        // 使用Jackson2JsonRedisSerialize 替换默认序列化
//        Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
//        ObjectMapper om = new ObjectMapper();
//        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
//        om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
//        jackson2JsonRedisSerializer.setObjectMapper(om);
//
//
//        //设置value的序列化方式
//        redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
//        //设置key的序列化方式
//        redisTemplate.setKeySerializer(new StringRedisSerializer());
//        redisTemplate.setHashKeySerializer(new StringRedisSerializer());
//        redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);

        //使用fastJson作为默认的序列化方式
        GenericFastJsonRedisSerializer genericFastJsonRedisSerializer = new GenericFastJsonRedisSerializer();
        redisTemplate.setDefaultSerializer(genericFastJsonRedisSerializer);
        redisTemplate.setValueSerializer(genericFastJsonRedisSerializer);
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        redisTemplate.setHashValueSerializer(genericFastJsonRedisSerializer);
        redisTemplate.setHashKeySerializer(new StringRedisSerializer());
        redisTemplate.afterPropertiesSet();

        return redisTemplate;

    }

    /**
     * 转换返回的object为json
     * @return
     */
    @Bean
    public HttpMessageConverters fastJsonHttpMessageConverters(){
        // 1、需要先定义一个converter 转换器
        FastJsonHttpMessageConverter fastConverter = new FastJsonHttpMessageConverter();
        // 2、添加fastJson 的配置信息,比如:是否要格式化返回的json数据
        FastJsonConfig fastJsonConfig = new FastJsonConfig();
        fastJsonConfig.setSerializerFeatures(SerializerFeature.PrettyFormat);
        // 3、在convert 中添加配置信息
        fastConverter.setFastJsonConfig(fastJsonConfig);
        // 4、将convert 添加到converters当中
        HttpMessageConverter<?> converter = fastConverter;
        return new HttpMessageConverters(converter);
    }


}

出自:https://www.cnblogs.com/ejiyuan/p/11014765.html
参考文档:https://blog.csdn.net/qq_26820793/article/details/125139773

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值