Spring Cache + Redis 使用

Spring Boot 2.2.1.RELEASE

1. Spring 缓存抽象

Spring从3.1开始定义了org.springframework.cache.Cache和org.springframework.cache.CacheManager接口来统一不同的缓存技术

Spring框架提供了对将缓存透明添加到现有Spring应用程序的支持。与事务支持类似,缓存抽象允许一致使用各种缓存解决方案,而对代码的影响最小。

每次调用需要缓存功能的方法时,Spring会检查指定参数的指定的目标方法是否已经被调用过;如果有就直接从缓存中获取方法调用后的结果,如果没有就调用方法并缓存结果后返回给用户,下次调用直接从缓存中获取。

使用Spring缓存抽象时我们需要关注以下两点:

  1. 确定方法需要被缓存以及他们的缓存策略;
  2. 缓存中读取之前缓存存储的数据

缓存注解和接口

名称 解释
@EnableCaching 开启基于注解的缓存
Cache 缓存接口,定义缓存操作。实现有:RedisCache、EhCacheCache、ConcurrentMapCache等\
CacheManager 缓存管理器,管理各种缓存(cache)组件
keyGenerator 缓存数据时key生成策略
serialize 缓存数据时value序列化策略
@CacheConfig 在类级别共享一些与缓存相关的常见设置
@Cacheable 创建缓存,主要针对方法配置,根据方法的请求参数对其进行缓存
@CachePut 更新缓存,而不会干扰方法的执行。与@Cacheable区别在于是否每次都调用方法,常用于更新
@CacheEvict 清空缓存

@Cacheable/@CachePut/@CacheEvict 主要的参数

名称 解释
value/cacheNames 缓存的名称,在 spring 配置文件中定义,必须指定至少一个
例如:@Cacheable(value=”mycache”)
@Cacheable(value={”cache1”,”cache2”}
key 缓存的 key,可以为空,如果指定要按照 SpEL 表达式编写,如果不指定,则缺省按照方法的所有参数进行组合
例如:@Cacheable(value=”testcache”,key=”#id”)
condition 缓存的条件,可以为空,使用 SpEL 编写,返回 true 或者 false,只有为 true 才进行缓存/清除缓存
例如:@Cacheable(value=”testcache”,condition=”#userName.length()>2”)
unless 否定缓存。当条件结果为TRUE时,就不会缓存。
@Cacheable(value=”testcache”,unless=”#userName.length()>2”)
allEntries(@CacheEvict ) 是否清空所有缓存内容,缺省为 false,如果指定为 true,则方法调用后将立即清空所有缓存
例如:@CachEvict(value=”testcache”,allEntries=true)
beforeInvocation(@CacheEvict) 是否在方法执行前就清空,缺省为 false,如果指定为 true,则在方法还没有执行的时候就清空缓存,缺省情况下,如果方法执行抛出异常,则不会清空缓存。
例如:@CachEvict(value=”testcache”,beforeInvocation=true)

2. Spring Cache + Redis 使用

添加Spring Data Redis相关依赖,Cache在Spring框架包中,不用单独添加

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

<!--spring2.0集成redis所需common-pool2-->
<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-pool2</artifactId>
    <version>2.4.2</version>
</dependency>

<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>fastjson</artifactId>
    <version>1.2.60</version>
</dependency>

<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <optional>true</optional>
</dependency>

application.yml 添加Cache和Redis环境配置

server:
  port: 8123

spring:
  cache:
    type: redis

  redis:
    # Redis默认情况下有16个分片,这里配置具体使用的分片,默认是0
    database: 0
    host: localhost
    port: 6379
    # 连接密码(默认为空)
    password:
    # 连接超时时间(毫秒)
    timeout: 10000ms
    lettuce:
      pool:
        # 连接池最大连接数(使用负值表示没有限制) 默认 8
        max-active: 8
        # 连接池最大阻塞等待时间(使用负值表示没有限制) 默认 -1
        max-wait: -1
        # 连接池中的最大空闲连接 默认 8
        max-idle: 8
        # 连接池中的最小空闲连接 默认 0
        min-idle: 0

添加配置

自定义key生成器,改变默认key生成策略

自定义缓存管理器,设置缓存时间,更改key和value序列化器

自定义redisTemplate,修改key和value的序列化器

@Configuration
// 开启基于注解的缓存
@EnableCaching
public class RedisConfig extends CachingConfigurerSupport {

    /**
     * Spring Cache 自定义key生成器,缓存数据时key生成策略
     * @return
     */
    @Bean
    @Override
    public KeyGenerator keyGenerator() {
        return ((target, method, params) -> {
            StringBuilder stringBuilder = new StringBuilder();
            stringBuilder.append(target.getClass().getName());
            stringBuilder.append(method.getName());

            for (Object obj : params) {
                stringBuilder.append(obj.toString());
            }
            return stringBuilder.toString();
        });
    }

    /**
     * Spring Cache 自定义缓存管理器,管理各种缓存(cache)组件
     * @param connectionFactory
     * @return
     */
    @Bean
    public CacheManager cacheManager(RedisConnectionFactory connectionFactory) {
        RedisCacheConfiguration redisCacheConfiguration = RedisCacheConfiguration.defaultCacheConfig();
        // 设置缓存的默认超时时间5分钟
        redisCacheConfiguration = redisCacheConfiguration.entryTtl(Duration.ofMinutes(5L))
                // 如果是空值,不缓存
                .disableCachingNullValues()
                // 设置key序列化器
                .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer()))
                // 设置value序列化器
                .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer((new GenericFastJsonRedisSerializer())));

        RedisCacheWriter redisCacheWriter = RedisCacheWriter.nonLockingRedisCacheWriter(connectionFactory);
        RedisCacheManager cacheManager = new RedisCacheManager(redisCacheWriter, redisCacheConfiguration);
        return cacheManager;
    }

    /**
     * Spring data Redis 自定义redisTemplate
     * @param factory
     * @return
     */
    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
        RedisTemplate<String, Object> template = new RedisTemplate();
        template.setConnectionFactory(factory);
        template.setKeySerializer(new StringRedisSerializer());
        template.setValueSerializer(new GenericFastJsonRedisSerializer());
        template.setHashKeySerializer(new StringRedisSerializer());
        template.setHashValueSerializer(new GenericFastJsonRedisSerializer());
        return template;
    }

}

测试用户类

@Data
@NoArgsConstructor
@AllArgsConstructor
public class User implements Serializable {
    private int id;
    private String name;
}

定义User接口

public interface UserService {
    User getUser(Integer id);
    List<User> getUserList();
    User updateUser(Integer id);
    void clearUserCache(Integer id);
    void clearAllCache();
}

在User实现类中使用缓存注解

cacheNames 即 value,定义缓存的名称,创建、更新和清除缓存都针对的缓存名

key 和 cacheNames 拼成 cacheNames::key,即为保存在Redis中的key

@Service
public class UserServiceImpl implements UserService {

    @Override
    @Cacheable(cacheNames = "user", key = "#id")
    public User getUser(Integer id) {
        User user = null;
        if (id == 1) {
            user = new User(1, "张一 key 1");
        } else if (id == 2) {
            user = new User(2, "张二 key 2");
        } else if (id == 3) {
            user = new User(3, "张三 key 3");
        }
        return user;
    }

    @Override
    @Cacheable(cacheNames = "userList")
    public List<User> getUserList() {

        List<User> userList = new ArrayList<>();

        User user1 = new User(1, "张三");
        User user2 = new User(2, "李四");
        User user3 = new User(3, "王五");

        userList.add(user1);
        userList.add(user2);
        userList.add(user3);

        return userList;
    }

    @Override
    // condition 定义更新条件,只有id为1才更新
    @CachePut(cacheNames = "user", condition = "#id == 1", key = "#id")
    public User updateUser(Integer id) {
        return new User(id, "更新 " + id + " 名称");
    }

    @Override
    // 根据user的id清空具体的id的缓存
    @CacheEvict(cacheNames = "user", key = "#id")
    public void clearUserCache(Integer id) {

    }

    @Override
    // 清空user下所有的缓存
    @CacheEvict(cacheNames = "user", allEntries=true)
    public void clearAllCache() {

    }
}

3. 测试

User的测试Controller

@RestController
@RequestMapping("/user")
public class UserController {

    @Autowired
    private UserService userService;

    @GetMapping("/getUser")
    public User getUser(@RequestParam("id") Integer id){
        return userService.getUser(id);
    }

    @GetMapping("/getUserList")
    public List<User> getUserList(){
        return userService.getUserList();
    }

    @GetMapping("/updateUser")
    public User updateUser(@RequestParam("id")Integer id) {
        return userService.updateUser(id);
    }

    @GetMapping("/clearUserCache")
    public void clearUserCache(@RequestParam("id") Integer id){
        userService.clearUserCache(id);
    }

    @GetMapping("/clearAllCache")
    public void clearAllCache(){
       userService.clearAllCache();
    }

}

创建user缓存
localhost:8123/user/getUser?id=1

指定了key,所以没有走生成key的方法;再次调用就没有走到具体的service方法中,直接缓存获取
创建自定义key缓存
创建userList缓存
localhost:8123/user/getUserList

未指定key,走自定义生成key
创建生成key缓存
更新user缓存
localhost:8123/user/updateUser?id=1

id为2和3,缓存没更新
更新用户1
更新用户2,3
清除user缓存
localhost:8123/user/clearUserCache?id=2

id为2的user缓存清空了
清空用户缓存
清除所有user缓存
localhost:8123/user/clearAllCache

只有cacheNames为user的缓存都被清除了,缓存名为userList的没有清除

所有可以使用@Caching 定义类级别的缓存名
清空所有用户缓存

参考:
史上最全的Spring Boot Cache使用与整合
Spring Cache 文档

发布了57 篇原创文章 · 获赞 11 · 访问量 9860

猜你喜欢

转载自blog.csdn.net/qq_36160730/article/details/103489682