多缓存配置
多缓存使用Redis数据库用作缓存存储,可根据自身业务配置多套不同名称的配置交替使用,从配置注入到使用如下。
- 第一步在配置文件 application.yaml 中 macula.redis 项下添加自己的Redis配置:
macula:
######## 缓存Redis配置 ##############
redis:
- name: cache
singleServerConfig:
address: ${macula.redis.cache.url}
password: ${macula.redis.cache.password}
- name: data
singleServerConfig:
address: ${macula.redis.data.url}
password: ${macula.redis.data.password}
- name: klock
singleServerConfig:
address: ${macula.redis.klock.url}
password: ${macula.redis.klock.password}
- name: demo
singleServerConfig:
address: ${macula.redis.demo.url}
password: ${macula.redis.demo.password}
项目启动时, Macula4架构会将 macula.redis 中所有的Redis项配置注册到 bean 实例中, Bean名称为 {redis.name} + “RedissonClient”, 如上demo则实例名称为:demoRedissonClient。具体实现代码可查阅 RedissonClientConfigurationRegistrar.class 。
- 第二步 使用demoRedissonClient 创建工厂实例与Redisson序列化
@Configuration
public class DemoRedisConfiguration {
@Bean(name = "demoRedisConnectionFactory")
public RedisConnectionFactory demoRedisConnectionFactory(@Qualifier("demoRedissonClient") RedissonClient redissonClient) {
return new RedissonConnectionFactory(redissonClient);
}
@Bean(name = "demoRedisTemplate")
public RedisTemplate<String, Object> demoRedisTemplate(@Qualifier("demoRedisConnectionFactory") RedisConnectionFactory demoRedisConnectionFactory) {
// TODO 读取配置好点(Class)kryo.register
KryoRedisSerializer<Object> kryoRedisSerializer = new KryoRedisSerializer<>(new Class<?> [] { Object.class});
RedisTemplate<String, Object> template = new RedisTemplate<>();
template.setConnectionFactory(demoRedisConnectionFactory);
// 设置值(value)的序列化采用FastJsonRedisSerializer。
template.setValueSerializer(kryoRedisSerializer);
template.setHashValueSerializer(kryoRedisSerializer);
// 设置键(key)的序列化采用StringRedisSerializer。
template.setKeySerializer(RedisSerializer.string());
template.setHashKeySerializer(RedisSerializer.string());
return template;
}
@Bean(name = "demoStringRedisTemplate")
public StringRedisTemplate demoStringRedisTemplate(@Qualifier("demoRedisConnectionFactory") RedisConnectionFactory demoRedisConnectionFactory) {
StringRedisTemplate template = new StringRedisTemplate();
template.setConnectionFactory(demoRedisConnectionFactory);
return template;
}
}
- 第三步 使用
@Resource(name = "demoStringRedisTemplate")
private StringRedisTemplate stringRedisTemplate;
多级缓存
Macula扩展了缓存功能,支持分布式环境的多级缓存框架,一级缓存使用Caffeine作为本地缓存,二级缓存使用redis作为集中式缓存,在配置文件 application.yaml 中 macula.redis 项下使用 - name: cache 为二级缓存数据库 。一级缓存和二级缓存的数据一致性是通过推和拉两种模式相结合的方式来实现的。推主要是基于redis的pub/sub机制,拉主要是基于消息队列和记录消费消息的偏移量来实现的。
支持
- 支持缓存命中率的监控统计,统计数据上报支持自定义扩展
- 支持缓存过期时间在注解上直接配置
- 支持缓存的自动刷新(当缓存命中并发现二级缓存将要过期时,会开启一个异步线程刷新缓存)
- 缓存Key支持SpEL表达式
- Redis支持Kryo、FastJson,默认设置值(value)的序列化采用FastJsonRedisSerializer,设置键(key)的序列化采用StringRedisSerializer。
- 支持同一个缓存名称设置不同的过期时间
- 支持禁用一级缓存,只使用二级缓存
- 通过允许存空值来解决缓存穿透问题
使用
直接在需要缓存的方法上加上Cacheable、CacheEvict、CachePut注解。
- Cacheable注解:
@Cacheable(value = "user:info", ignoreException = false,
firstCache = @FirstCache(expireTime = 4, timeUnit = TimeUnit.SECONDS),
secondaryCache = @SecondaryCache(expireTime = 10, preloadTime = 3,
forceRefresh = true, timeUnit = TimeUnit.SECONDS))
public User getUserNoKey(long userId, String[] lastName) {
logger.debug("测试没有配置key的缓存方法,参数是基本类型和数组的缓存缓存方法");
User user = new User();
user.setUserId(userId);
user.setAge(31);
user.setLastName(lastName);
return user;
}
- CachePut注解
@CachePut(value = "user:info", key = "#userId", ignoreException = false,
firstCache = @FirstCache(expireTime = 4, timeUnit = TimeUnit.SECONDS),
secondaryCache = @SecondaryCache(expireTime = 10, preloadTime = 3, forceRefresh = true, timeUnit = TimeUnit.SECONDS))
public User putUser(long userId) {
User user = new User();
user.setUserId(userId);
user.setAge(31);
user.setLastName(new String[]{"w", "y", "h"});
return user;
}
- CacheEvict注解
@CacheEvict(value = "user:info", key = "#userId")
public void evictUser(long userId) {
}
@CacheEvict(value = "user:info", allEntries = true)
public void evictAllUser() {
}
注解说明
@Cacheable
表示用的方法的结果是可以被缓存的,当该方法被调用时先检查缓存是否命中,如果没有命中再调用被缓存的方法,并将其返回值放到缓存中。
名称 | 默认值 | 说明 | |||
---|---|---|---|---|---|
value | 空字符串数组 | 缓存名称,cacheNames的别名 | |||
cacheNames | 空字符串数组 | 缓存名称 | |||
key | 空字符串 | 缓存key,支持SpEL表达式 | |||
depict | 空字符串 | 缓存描述(在缓存统计页面会用到) | |||
ignoreException | true | 是否忽略在操作缓存中遇到的异常,如反序列化异常 | |||
firstCache | 注解,一级缓存配置 | ||||
secondaryCache | 注解,二级缓存配置 |
@FirstCache
一级缓存配置项
名称 | 默认值 | 说明 |
---|---|---|
initialCapacity | 10 | 缓存初始Size |
maximumSize | 5000 | 缓存最大Size |
expireTime | 9 | 缓存有效时间 |
timeUnit | TimeUnit.MINUTES | 时间单位,默认分钟 |
expireMode | ExpireMode.WRITE | 缓存失效模式,ExpireMode.WRITE:最后一次写入后到期失效,ExpireMode.ACCESS:最后一次访问后到期失效 |
@SecondaryCache
二级缓存配置项
名称 | 默认值 | 说明 |
---|---|---|
expireTime | 5 | 缓存有效时间 |
preloadTime | 1 | 缓存主动在失效前强制刷新缓存的时间,建议是 expireTime * 0.2 |
timeUnit | TimeUnit.HOURS | 时间单位,默认小时 |
forceRefresh | false | 是否强制刷新(直接执行被缓存方法) |
isAllowNullValue | false | 是否允许缓存NULL值 |
magnification | 1 | 非空值和null值之间的时间倍率,默认是1。isAllowNullValue=true才有效 |
magnification | 1 | 非空值和null值之间的时间倍率,默认是1。isAllowNullValue=true才有效 |
@CachePut
将数据放到缓存中
名称 | 默认值 | 说明 |
---|---|---|
value | 空字符串数组 | 缓存名称,cacheNames的别名 |
cacheNames | 空字符串数组 | 缓存名称 |
key | 空字符串 | 缓存key,支持SpEL表达式 |
depict | 空字符串 | 缓存描述(在缓存统计页面会用到) |
ignoreException | true | 是否忽略在操作缓存中遇到的异常,如反序列化异常 |
firstCache | 注解,一级缓存配置 | |
secondaryCache | 注解,二级缓存配置 |
@CacheEvict
删除缓存
名称 | 默认值 | 说明 |
---|---|---|
value | 空字符串数组 | 缓存名称,cacheNames的别名 |
cacheNames | 空字符串数组 | 缓存名称 |
key | 空字符串 | 缓存key,支持SpEL表达式 |
allEntries | false | 是否删除缓存中所有数据,默认情况下是只删除关联key的缓存数据,当该参数设置成 true 时 key 参数将无效 |
ignoreException | true | 是否忽略在操作缓存中遇到的异常,如反序列化异常 |