随便画的,简单来说,工具先从 一级缓存取起,也就是本地缓存,如果缓存命中,就可以直接返回;如果一级缓存没有,就会去redis找,再不行就走传统业务逻辑。这种缓存比单一的缓存工具比起来具有以下特点:
但跟所有缓存框架一样,缓存只适合非关键数据,因为缓存更新多少具有延迟性。
缓存的更新比获取更复杂一点,它存在多种情况:
@Bean
RedissonClient redissonClient() {
Config config = new Config();
SingleServerConfig serverConfig = config.useSingleServer()
.setAddress("redis://" + redissonProperties.getHost() + ":" + redissonProperties.getPort())
.setTimeout(redissonProperties.getTimeout())
.setConnectionPoolSize(redissonProperties.getConnectionPoolSize())
.setConnectionMinimumIdleSize(redissonProperties.getConnectionMinimumIdleSize());
if (StringUtils.isNotBlank(redissonProperties.getPassword())) {
serverConfig.setPassword(redissonProperties.getPassword());
}
return Redisson.create(config);
}
@Component
@Slf4j
public class SecondLevelCacheUtil {
//为避免key冲突,key的设置应该规范
public static final String BRAINTRAIN = "braintrain:";
public static final String REDIS_TOPIC_PUT = BRAINTRAIN + "putTopic:";
public static final String REDIS_TOPIC_DELETE = BRAINTRAIN + "deleteTopic:";
@Autowired
CustomsProperties customsProperties;
@Autowired
RedissonClient redissonClient;
private Cache cache;
@PostConstruct
void init() {
log.info("SecondLevelCacheUtil init");
cache = Caffeine.newBuilder()
.expireAfterWrite(customsProperties.getRedisFirstCacheTime(), TimeUnit.MILLISECONDS)
.build();
// 监听删除缓存事件,及时清除本地一级缓存
RTopic deleteTopic = redissonClient.getTopic(REDIS_TOPIC_DELETE + customsProperties.getAppName());
deleteTopic.addListener((channel, message) -> {
log.info("first cache delete {}", message);
cache.invalidate(message);
});
// 监听新增缓存事件,及时新增本地一级缓存
RTopic putTopic = redissonClient.getTopic(REDIS_TOPIC_PUT + customsProperties.getAppName());
putTopic.addListener((channel, message) -> {
if (StringUtils.isNotBlank(message)) {
log.info("first cache put {}", message);
String[] split = message.split("\\|\\|");
cache.put(split[0], split[1]);
}
});
log.info("SecondLevelCacheUtil done");
}
public T get(String key, Class clazz) {
try {
if (StringUtils.isBlank(key) || !key.startsWith(BRAINTRAIN)) {
return null;
}
//一级缓存取不到时,调用getByRedis()取二级缓存,由Caffeine原生提供机制
String json = cache.get(key, k -> getByRedis(k));
if (StringUtils.isNotBlank(json)) {
return JSON.parseObject(json, clazz);
}
} catch (Exception e) {
log.warn("SecondLevelCacheUtil get e={}", e);
}
return null;
}
public void delete(String key) {
try {
if (StringUtils.isBlank(key) || !key.startsWith(BRAINTRAIN)) {
return;
}
RBucket
3.部分设置项
@Component
@Data
public class CustomsProperties {
//一级缓存失效时间
@Value("${braintrain.redisFirstCacheTime: 180000}")
Long redisFirstCacheTime;
//二级缓存失效时间
@Value("${braintrain.redisSecondCacheTime: 2592000000}")
Long redisSecondCacheTime;
}
2019.1.3
我已经将工具组件化,详情看新博文
spring之我见–spring的组件化(以logging日志初始化为例)