当前位置: > > > SpringBoot - 缓存的使用详解3(使用Redis集群缓存)

SpringBoot - 缓存的使用详解3(使用Redis集群缓存)

    相较于于 Redis 单机缓存,Redis 集群缓存的配置要复杂一些(缓存使用方面还是一样),但具有良好的扩展性和安全性。下面通过样例演示具体操作步骤。

三、使用 Redis 集群缓存

1,搭建 Redis 集群

本案例采用的 Redis 集群由 8Redis 实例组成,4 4 从,端口从 80018008,具体搭建步骤可以参考我之前写的文章:

2,添加依赖 

首先编辑项目的 pom.xml 文件,添加 spring-boot-starter-cache 依赖以及 Redis 依赖:
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<dependency>
    <groupId>redis.clients</groupId>
    <artifactId>jedis</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.data</groupId>
    <artifactId>spring-data-redis</artifactId>
</dependency>
<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-pool2</artifactId>
</dependency>

3,配置集群

    接着在 Spring Boot 项目中配置 Redis 连接信息以及 RedisConfig 完成对 Redis 的配置(使得能够在 Spring Boot 中通过 RedisTemplate 访问成功),具体步骤可以参考我之前写的文章:

4,进行缓存配置

当集群搭建成功,并且能够从 Spring Boot 项目中访问 Redis 集群后,只需要进行简单的 Redis 缓存配置即可,代码如下:
(1)在之前配置 Redis 集群时,已经向 Spring 容器中注册了一个 JedisConnectionFactory 的实例,这里将之注入到 RedisCacheConfig 中使用(RedisConnectionFactoryJedisConnectionFactory 的父类)。
(2)RedisCacheConfig 中主要提供 RedisCacheManager 的实例,该实例的构建需要三个参数:
  • 第一个参数是一个 cacheWriter,直接通过 nonLockingRedisCacheWriter 方法构造出来即可。
  • 第二个参数是默认的缓存配置。默认的缓存过期时间为 0(永不过期),并自动开启 key 的前缀(默认前缀是“缓存名::”)
  • 第三个参数是提前定义好的缓存配置。它是一个 Map 类型的参数,该 Map 中的 key 就是指缓存名字,value 就是该名称的缓存所对应的缓存配置,例如 key 的前缀、缓存过期时间等。(如果某个缓存名不存在 configMap 中,则使用默认的缓存策略)
@Configuration
public class RedisCacheConfig {
    @Autowired
    @Qualifier("jedisConnectionFactory")
    RedisConnectionFactory conFactory;

    @Bean
    RedisCacheManager redisCacheManager() {
        // 定义缓存配置参数
        Map<String, RedisCacheConfiguration> configMap = new HashMap<>();
        // 设置缓存名称为 c1 的缓存配置参数
        RedisCacheConfiguration redisCacheConfig =
                RedisCacheConfiguration.defaultCacheConfig()
                        .prefixKeysWith("hangge:") // key的前缀
                        .disableCachingNullValues() // 禁止缓存一个 null 
                        .entryTtl(Duration.ofMinutes(30)); // 缓存过期时间(30分钟)
        configMap.put("c1", redisCacheConfig);

        // 创建一个 cacheWriter
        RedisCacheWriter cacheWriter =
                RedisCacheWriter.nonLockingRedisCacheWriter(conFactory);

        // 创建一个 redisCacheManager 并返回
        RedisCacheManager redisCacheManager =
                new RedisCacheManager(
                        cacheWriter,
                        RedisCacheConfiguration.defaultCacheConfig(), // 默认的缓存配置
                        configMap);
        return redisCacheManager;
    }
}

5,开启缓存

在项目的入口类上添加 @EnableCaching 注解开启缓存,代码如下:
@SpringBootApplication
@EnableCaching
public class DemoApplication {
    public static void main(String[] args) {
        ConfigurableApplicationContext context
                = SpringApplication.run(DemoApplication.class, args);
    }
}

6,开始测试

(1)首先我们创建一个 BookDao 并使用缓存:
@Repository
public class BookDao {

    @Cacheable(value = "c1")
    public String getBookById(Integer id) {
        System.out.println("getBookById");
        return "三国演义";
    }

    @CachePut(value = "c1")
    public String updateBookById(Integer id) {
        System.out.println("updateBookById");
        return "新版三国演义";
    }

    @CacheEvict(value = "c1")
    public void deleteBookById(Integer id) {
        System.out.println("deleteBookById");
    }

    @Cacheable(value = "c2")
    public String getBookById2(Integer id) {
        System.out.println("getBookById2");
        return "西游记";
    }
}

(3)创建一个测试 ControllerBookDao 中的方法进行测试:
@RestController
public class HelloController {

    @Autowired
    BookDao bookDao;

    @GetMapping("/test")
    public void test() {
        // 连续获取两次数据
        System.out.println("-- 连续获取两次数据 --");
        bookDao.getBookById(100);
        String book1 = bookDao.getBookById(100);
        System.out.println(book1);

        // 更新后再次获取数据
        System.out.println("-- 更新后再次获取数据 --");
        bookDao.updateBookById(100);
        String book2 = bookDao.getBookById(100);
        System.out.println(book2);

        // 删除后再次获取数据
        System.out.println("-- 删除后再次获取数据 --");
        bookDao.deleteBookById(100);
        String book3 = bookDao.getBookById(100);
        System.out.println(book3);

        // 获取另一个缓存数据
        System.out.println("-- 获取另一个缓存数据 --");
        String book4 = bookDao.getBookById2(200);
        System.out.println(book4);
    }
}

(4)访问这个接口,可以看到控制台打印日志如下:
  • 一开始执行了两个査询,但是查询方法只打印了一次,因为第二次使用了缓存。
  • 接下来执行更新方法,更新方法中不仅更新数据,也更新了缓存,所以在最后的査询方法中,查询方法日志没打印,说明该方法没执行,而是使用了缓存中的数据,而缓存中的数据已经被更新了。
  • 再接下来执行了删除方法,删除方法执行完之后再次执行查询,查询方法又被执行了,因为在删除方法中缓存已经被删除了。
  • 最后查询一个使用其它缓存名称的数据,由于当前还不存在对应的缓存数据,则会执行查询方法。

(2)查看 Redis 服务器的缓存结果,可以发现:
  • c1 缓存由于前面自定义了缓存配置,则前缀变成自定义的“hangge:
  • c2 由于没有对应的自定义设置,则使用默认前缀,即“缓存名::

附:自定义缓存 key 的生成器 KeyGenerator

    根据前面介绍可知,默认情况下缓存的 key 是方法的参数。如果不想使用默认的 key,可以使用自定义 key(使用参数定义 key 的方式、或者使用 root 对象来生成 key)。
    如果这些 key 不能满足开发需求,我们也可以自定义缓存 key 的生成器 KeyGenerator

1,创建自定义 KeyGenerator

自定义的 MyKeyGenerator 实现 KeyGenerator 接口,然后实现该接口中的 generate 方法。
    generate 方法的三个参数分别是当前对象、当前请求的方法以及方法的参数,开发者可根据这些信息纽成一个新的 key 返回,返回值就是缓存的 key
@Component
public class MyKeyGenerator implements KeyGenerator {
    @Override
    public Object generate(Object target, Method method, Object... params) {
        return Arrays.toString(params);
    }
}

2,使用自定义的 KeyGenerator

(1)使用时我们只需要在 @Cacheable 注解中引用 MyKeyGenermor 实例即可。
@Repository
public class BookDao {

    @Autowired
    MyKeyGenerator myKeyGenerator;

    @Cacheable(value = "c1", keyGenerator = "myKeyGenerator")
    public String getBookById(Integer id) {
        System.out.println("getBookById");
        return "三国演义";
    }
}

(2)调用这个缓存方法后可以看到对应的 key 变成如下形式:
评论0