## tio-boot 内置 CacheUtils
### 概述
tio-utils 内置了 CacheUtils 用户提供对缓存数据的支持,提供的工具类如下,tio-boot 已经内置了 tio-utils,所以不需要添加 tio-utils 的依赖.但是需要添加对于缓存库的依赖
- com.litongjava.tio.utils.cache.caffeine.CaffeineCache
- com.litongjava.tio.utils.cache.guava.GuavaCache
- com.litongjava.tio.utils.cache.caffeineredis.CaffeineRedisCache
- com.litongjava.tio.utils.cache.guavaredis.GuavaRedisCache
- com.litongjava.tio.utils.cache.j2cache.J2Cache
- com.litongjava.tio.utils.cache.redis.RedisCache
下面演示一下 CaffeineCache,RedisCache,CaffeineRedisCache 的使用
### CacheUtils
com.litongjava.tio.utils.cache.CacheUtils 提供了 get 方法,方法签名如下
``` public static <T extends Serializable> T get(ICache cache, String cacheKey, boolean putTempToCacheIfNull,FirsthandCreater<T> firsthandCreater); ```
方法解释:
根据 cacheKey 从缓存中获取对象,如果缓存中没有该 key 对象,则用 firsthandCreater 获取对象,并将对象用 cacheKey 存于 cache 中
### 缓存数据到 Caffeine
#### 添加依赖
tio-utils 虽然提供了对 caffeine 的支持,但是并没有继承 caffeine 依赖,所以添加 caffeine 依赖,推荐 2.x 版本,因为 3.x 版已经不支持 jdk 1.8
``` <dependency> <groupId>com.github.ben-manes.caffeine</groupId> <artifactId>caffeine</artifactId> <version>2.9.3</version> </dependency> ```
#### 配置类 CacheNameConfig
CacheName,使用默认的 com.litongjava.tio.utils.cache.CacheName
CacheNameService,使用默认的 com.litongjava.tio.utils.cache.CacheNameService
``` package com.litongjava.tio.web.hello.config; import java.util.Collection; import com.litongjava.jfinal.aop.annotation.Bean; import com.litongjava.jfinal.aop.annotation.Configuration; import com.litongjava.tio.utils.cache.CacheName; import com.litongjava.tio.utils.cache.CacheNameService; import com.litongjava.tio.utils.cache.caffeine.CaffeineCacheFactory; import com.litongjava.tio.utils.time.Time; @Configuration public class CacheNameConfig { @Bean public CacheNameService register() { CacheName demo = new CacheName("demo", null, Time.MINUTE_1 * 10); CacheNameService cacheNameService = new CacheNameService(); cacheNameService.add(demo); Collection<CacheName> names = cacheNameService.cacheNames(); for (CacheName cacheName : names) { CaffeineCacheFactory.INSTANCE.register(cacheName); } return cacheNameService; } } ```
package com.litongjava.tio.web.hello.controller; import com.litongjava.tio.http.server.annotation.RequestPath; import com.litongjava.tio.utils.cache.CacheUtils; import com.litongjava.tio.utils.cache.FirsthandCreater; import com.litongjava.tio.utils.cache.ICache; import com.litongjava.tio.utils.cache.caffeine.CaffeineCacheFactory; import lombok.extern.slf4j.Slf4j; @RequestPath("/cache/caffeine") @Slf4j public class CacheCaffeineTestController { public Object test2() { // firsthandCreater用户查询数据库 FirsthandCreater<String> firsthandCreater = new FirsthandCreater<String>() { @Override public String create() { log.info("查询数据库"); return "index"; } }; // 通常是tableName String cacheName = "demo"; ICache cache = CaffeineCacheFactory.INSTANCE.getCache(cacheName); String key = "key"; boolean putTempToCacheIfNull = false; String value = CacheUtils.get(cache, key, putTempToCacheIfNull, firsthandCreater); return value; } } ```
访问测试 http://localhost/cache/caffeine/test2
#### CacheNameService 类
- **目的**: 管理缓存名称和相关设置。
- **成员变量**: 包含一个 `CacheName` 类型的 `demo` 对象,初始化为一个缓存名称为 "demo",生命周期为 10 分钟(`Time.MINUTE_1 * 10`)的缓存。
- **方法 `cacheNames()`**: 返回一个包含 `demo` 缓存配置的列表。
#### CacheNameConfig 类
- **目的**: 配置缓存。
- **方法 `register()`**:
- 创建 `CacheNameService` 实例。
- 遍历 `cacheNames()` 方法返回的所有缓存名称。
- 对每个缓存名称,使用 `CaffeineCacheFactory.register` 方法注册缓存,设定其生存和空闲时间。
- 返回 `CacheNameService` 实例。
#### CacheTestController 类
- **目的**: 演示如何使用缓存。
- **方法 `test2()`**:
- 定义 `FirsthandCreater` 匿名类实例,用于在缓存未命中时获取数据(例如从数据库中)。
- 通过 `Aop.get(CacheNameService.class)` 获取 `CacheNameService` 实例,并从中获取 `demo` 缓存的名称。
- 使用 `CaffeineCache.getCache` 方法获取对应名称的缓存实例。
- 使用 `CacheUtils.get` 方法从缓存中获取键为 "key" 的数据。如果缓存中没有该数据,则会调用 `FirsthandCreater` 实例的 `create` 方法来获取数据并缓存它。
- 返回获取的值。
#### 总结
整体而言,这些代码段展示了如何在 Tio 框架中配置和使用 Caffeine 缓存。它们通过 `CacheNameService` 类管理缓存配置,`CacheNameConfig` 类负责缓存的注册,而 `CacheTestController` 类演示了如何实际从缓存中获取数据。这是一个典型的缓存使用场景,特别是在需要高效读取频繁访问数据的应用中。
### 缓存数据到 redis
使用 tio-utils 提供的 CacheUtils 缓存数据到 redis
#### 添加依赖
因为需要使用 redisson 连接 redis,所以需要添加 redisson 依赖
``` <dependency> <groupId>org.redisson</groupId> <artifactId>redisson</artifactId> <version>3.16.0</version> </dependency> ```
#### RedissonConfig 配置类
``` package com.litongjava.tio.boot.hello.config; import com.litongjava.jfinal.aop.annotation.Bean; import com.litongjava.jfinal.aop.annotation.Configuration; import org.redisson.Redisson; import org.redisson.api.RedissonClient; import org.redisson.config.Config; @Configuration public class RedissonConfig { @Bean(destroyMethod = "shutdown", priority = 10) public RedissonClient redissonClient() { Config config = new Config(); config.useSingleServer().setAddress("redis://localhost:6379").setDatabase(0); // 如果你的 Redis 设置了密码 // .setPassword("yourPassword"); RedissonClient client = null; try { client = Redisson.create(config); } catch (Exception e) { e.printStackTrace(); } return client; } } ```
#### CacheNameConfig 配置类
``` package com.litongjava.tio.web.hello.config; import java.util.Collection; import org.redisson.api.RedissonClient; import com.litongjava.jfinal.aop.Aop; import com.litongjava.jfinal.aop.annotation.Bean; import com.litongjava.jfinal.aop.annotation.Configuration; import com.litongjava.tio.utils.cache.CacheName; import com.litongjava.tio.utils.cache.CacheNameService; import com.litongjava.tio.utils.cache.caffeine.CaffeineCacheFactory; import com.litongjava.tio.utils.cache.redis.RedisCacheFactory; import com.litongjava.tio.utils.time.Time; @Configuration public class CacheNameConfig { @Bean public CacheNameService register() { //设置CacheName CacheName demo = new CacheName("demo", null, Time.MINUTE_1 * 10); //将CacheName添加到CacheNameService CacheNameService cacheNameService = new CacheNameService(); cacheNameService.add(demo); //将redissonClient添加到RedisCacheFactory RedissonClient redissonClient = Aop.get(RedissonClient.class); RedisCacheFactory.INSTANCE.setRedisson(redissonClient); //注册cacheName Collection<CacheName> names = cacheNameService.cacheNames(); for (CacheName cacheName : names) { CaffeineCacheFactory.INSTANCE.register(cacheName); RedisCacheFactory.INSTANCE.register(cacheName); } return cacheNameService; } } ```
#### 测试 Controller
``` package com.litongjava.tio.web.hello.controller; import com.litongjava.tio.http.server.annotation.RequestPath; import com.litongjava.tio.utils.cache.CacheUtils; import com.litongjava.tio.utils.cache.FirsthandCreater; import com.litongjava.tio.utils.cache.ICache; import com.litongjava.tio.utils.cache.redis.RedisCacheFactory; import lombok.extern.slf4j.Slf4j; @RequestPath("/cache/redis") @Slf4j public class CacheRedisTestController { public Object test3() { // firsthandCreater用户查询数据库 FirsthandCreater<String> firsthandCreater = new FirsthandCreater<String>() { @Override public String create() { log.info("查询数据库"); return "index"; } }; String cacheName = "demo"; ICache cache = RedisCacheFactory.INSTANCE.getCache(cacheName); String key = "key"; boolean putTempToCacheIfNull = false; String value = CacheUtils.get(cache, key, putTempToCacheIfNull, firsthandCreater); return value; } } ```
#### 访问测试
http://localhost/cache/redis/test3
代码展示了如何在 Tio 框架中使用 Redis 作为缓存解决方案。以下是对代码的详细解释:
#### RedissonConfig 类
- **目的**: 配置 Redisson 客户端以连接 Redis 服务器。
- **方法 `redissonClient()`**:
- 使用 `Config` 类创建 Redis 配置,指定 Redis 服务器地址和数据库索引。
- 如果 Redis 设置了密码,可以通过 `.setPassword("yourPassword")` 方法设置。
- 创建 `RedissonClient` 实例并返回。
- `priority = 10` 指定这个 Bean 的初始化优先级,值越小优先级越高,确保在其他依赖 RedissonClient 的 Bean 之前初始化。
#### CacheNameConfig 类
- **目的**: 配置缓存名称和设置。
- **方法 `register()`**:
- 获取 `RedissonClient` 实例。
- 创建 `CacheNameService` 实例,然后获取其提供的缓存配置列表。
- 遍历列表,使用 `RedisCache.register` 方法为每个缓存名称注册 Redis 缓存,指定存活时间和空闲时间。
- 返回 `CacheNameService` 实例。
#### CacheTestController 类
- **目的**: 演示如何使用缓存。
- **方法 `test3()`**:
- 定义 `FirsthandCreater` 匿名类,用于在缓存未命中时获取数据(比如从数据库获取)。
- 通过 `Aop.get(CacheNameService.class)` 获取 `CacheNameService` 实例,进而获得 `demo` 缓存的名称。
- 使用 `RedisCache.getCache` 方法获取对应名称的缓存实例。
- 使用 `CacheUtils.get` 方法从缓存中获取键为 "key" 的数据。如果缓存中没有该数据,则会调用 `FirsthandCreater` 实例的 `create` 方法来获取数据,并将其缓存。
- 返回获取的值。
#### 总结
这段代码演示了如何在 Tio 框架中配置和使用 Redis 作为缓存解决方案。它使用 RedissonClient 连接到 Redis 服务器,并通过 CacheNameService 管理缓存的不同配置。CacheTestController 类演示了如何在实际应用中从缓存中读取数据,如果缓存中没有数据,会从数据库中获取并缓存。这种方式在需要高效读取频繁访问数据的应用中非常有用。
### 使用 CacheUtils 整合 caffeine 和 redis 实现的两级缓存
#### 配置类 CacheNameConfig
``` package com.litongjava.tio.web.hello.config; import java.util.Collection; import org.redisson.api.RedissonClient; import com.litongjava.jfinal.aop.Aop; import com.litongjava.jfinal.aop.annotation.Bean; import com.litongjava.jfinal.aop.annotation.Configuration; import com.litongjava.tio.utils.cache.CacheName; import com.litongjava.tio.utils.cache.CacheNameService; import com.litongjava.tio.utils.cache.caffeineredis.CaffeineRedisCacheFactory; import com.litongjava.tio.utils.time.Time; @Configuration public class CacheNameConfig { @Bean public CacheNameService register() { //设置CacheName CacheName demo = new CacheName("demo", null, Time.MINUTE_1 * 10); //将CacheName添加到CacheNameService CacheNameService cacheNameService = new CacheNameService(); cacheNameService.add(demo); //将redissonClient添加到CaffeineRedisCacheFactory RedissonClient redissonClient = Aop.get(RedissonClient.class); CaffeineRedisCacheFactory.INSTANCE.init(redissonClient); //注册cacheName Collection<CacheName> names = cacheNameService.cacheNames(); for (CacheName cacheName : names) { //CaffeineCacheFactory.INSTANCE.register(cacheName); //RedisCacheFactory.INSTANCE.register(cacheName); CaffeineRedisCacheFactory.INSTANCE.register(cacheName); } return cacheNameService; } } ```
#### 测试类 CacheCaffeineRedisTestController
``` package com.litongjava.tio.web.hello.controller; import com.litongjava.tio.http.server.annotation.RequestPath; import com.litongjava.tio.utils.cache.CacheUtils; import com.litongjava.tio.utils.cache.FirsthandCreater; import com.litongjava.tio.utils.cache.ICache; import com.litongjava.tio.utils.cache.caffeineredis.CaffeineRedisCacheFactory; import lombok.extern.slf4j.Slf4j; @RequestPath("/cache/caffeine/redis") @Slf4j public class CacheCaffeineRedisTestController { public Object test() { // firsthandCreater用户查询数据库 FirsthandCreater<String> firsthandCreater = new FirsthandCreater<String>() { @Override public String create() { log.info("查询数据库"); return "index"; } }; String cacheName = "demo"; ICache cache = CaffeineRedisCacheFactory.INSTANCE.getCache(cacheName); String key = "key"; boolean putTempToCacheIfNull = false; String value = CacheUtils.get(cache, key, putTempToCacheIfNull, firsthandCreater); return value; } } ```
访问 http://localhost/cache/caffeine/redis/test 查看测试结果