itwolf项目名称,springboot,springcloud,l2cache缓存
1、依赖
<dependency>
<groupId>com.coy.l2cache</groupId>
<artifactId>l2cache-spring-boot-starter</artifactId>
<version>1.0.13</version>
</dependency>
2、代码配置
RedissonConfig.class
import com.alibaba.cloud.nacos.NacosConfigProperties;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.nacos.api.exception.NacosException;
import lombok.extern.slf4j.Slf4j;
import org.redisson.Redisson;
import org.redisson.api.RedissonClient;
import org.redisson.codec.JsonJacksonCodec;
import org.redisson.config.Config;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import javax.annotation.Resource;
import java.io.IOException;
import java.io.InputStream;
/**
* Redisson 配置
*
* @author ITwolf
* @date 2022/01/22 15:32
*/
@Slf4j
@Configuration
public class RedissonConfig {
/**
*
*/
@Value("${redisson.yaml.config:redisson.yaml}")
private String redissonYamlConfig;
@Resource
NacosConfigProperties nacosConfigProperties;
@Bean
@ConditionalOnMissingBean({RedissonClient.class})
public RedissonClient redissonClient() throws IOException, NacosException {
// 此方式可获取到springboot打包以后jar包内的资源文件
InputStream is = Thread.currentThread().getContextClassLoader().getResourceAsStream(this.redissonYamlConfig);
if (null != is) {
Config redissonConfig = Config.fromYAML(is);
return Redisson.create(redissonConfig);
}
// 扩展:针对redisson.yaml放到nacos统一配置管理后的扩展
NacosConfigProperties.Config nacosConfig = null;
log.info("打印读取nacos配置,{}", nacosConfigProperties);
log.info("打印读取redissonYamlConfig配置,{}", redissonYamlConfig);
for (NacosConfigProperties.Config config : nacosConfigProperties.getExtConfig()) {
if (redissonYamlConfig.equalsIgnoreCase(config.getDataId())) {
nacosConfig = config;
break;
}
}
String group = null != nacosConfig ? null : nacosConfig.getGroup();
String configYaml = nacosConfigProperties.configServiceInstance().getConfig(redissonYamlConfig, group, 3000);
log.info("read {} from nacos", redissonYamlConfig);
if (null == configYaml) {
throw new IllegalStateException("nacos " + redissonYamlConfig + " not config");
}
Config redissonConfig = Config.fromYAML(configYaml);
// 强制设置默认的codec为JsonJacksonCodec,以便和旧系统中RedisTemplate的GenericJackson2JsonRedisSerializer序列化反序列化保持一致
redissonConfig.setCodec(new JsonJacksonCodec());
RedissonClient redissonClient = Redisson.create(redissonConfig);
return redissonClient;
}
}
cache.class
import com.coy.l2cache.Cache;
import com.coy.l2cache.cache.CompositeCache;
import com.coy.l2cache.cache.Level2Cache;
import com.coy.l2cache.spring.L2CacheCacheManager;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
/**
* @author ITwolf
* @date 2022/01/20 15:00
*/
@Component
public class L2cache {
@Autowired
L2CacheCacheManager l2CacheCacheManager;
public Level2Cache getLevel2Cache(String cacheName) {
Cache l2cache = (Cache) l2CacheCacheManager.getCache(cacheName).getNativeCache();
if (l2cache instanceof Level2Cache) {
return (Level2Cache) l2cache;
}
if (l2cache instanceof CompositeCache) {
CompositeCache compositeCache = (CompositeCache) l2cache;
return compositeCache.getLevel2Cache();
}
throw new BusinessException("未找到Level2Cache对象,请检查缓存配置是否正确");
}
}
CacheService.class
/**
* 缓存 接口
* 基于业务维度标准化缓存操作
*
* @param <K> 表示相关的业务要素,可以是单个字段,也可以是一个对象。由开发人员在实现类中自己定义。
* @param <R> 表示返回的缓存数据
* @author ITwolf
* @date 2022/01/20 12:36
*/
public interface CacheService<K, R> {
/**
* 获取缓存名字
*/
String getCacheName();
/**
* 构建缓存key
*/
default String buildCacheKey(K key) {
return null;
}
/**
* 获取缓存
*/
R get(K key);
/**
* 获取或加载缓存,若缓存不存在,则从加载并设置到缓存,并返回
*/
R getOrLoad(K key);
/**
* 设置指定key的缓存项
*/
R put(K key, R value);
/**
* 仅当之前没有存储指定key的value时,才存储由指定key映射的指定value
*/
default boolean putIfAbsent(K key, R value) {
return false;
}
/**
* 重新加载缓存(存在则替换,不存在则设置)
*/
R reload(K key);
/**
* 淘汰缓存
*/
void evict(K key);
/**
* 判断key是否存在
*/
boolean isExists(K key);
}
3、nacos配置
itwolf-redisson.yml
singleServerConfig:
address: redis://localhost:6379
password: 123456
# default 10000 milliseconds
idleConnectionTimeout: 10000
# default 10000 milliseconds
connectTimeout: 5000
# default 3000 milliseconds
timeout: 3000
# default 3
retryAttempts: 3
# default 1500 milliseconds
retryInterval: 1500
# default 5
subscriptionsPerConnection: 5
# default null
clientName: null
# default 1
subscriptionConnectionMinimumIdleSize: 1
# default 50
subscriptionConnectionPoolSize: 50
# default 32
connectionMinimumIdleSize: 32
# default 64
connectionPoolSize: 300
# default 0
database: 0
# default 16, 0 means current_processors_amount * 2
threads: 32
# default 32, 0 means current_processors_amount * 2
nettyThreads: 64
# key/value codec, default JsonJacksonCodec
# codec: !<org.redisson.codec.JsonJacksonCodec> {}
注:redis密码等参数按照相关信息配置好
itwolf.yaml
# l2 cache
l2cache:
config:
allowNullValues: true
nullValueExpireTimeSeconds: 60
# composite redis
cacheType: redis
composite:
l1CacheType: caffeine
l2CacheType: redis
caffeine:
autoRefreshExpireCache: true
refreshPoolSize: 8
refreshPeriod: 10
defaultSpec: initialCapacity=16,maximumSize=5000,refreshAfterWrite=30m,recordStats
specs:
brandCache: initialCapacity=16,maximumSize=5000,refreshAfterWrite=30m,recordStats
redis:
tryLock: true
# 5m=300000, 30m=1800000
expireTime: 60000
redissonYamlConfig: ${spring.application.name}-redisson.yml
cacheSyncPolicy:
type: redis
topic: user_l2cache
要有远程服务 cn.xxxxx.service.user
UserFeignClient userFeignClient
以下是UserByUnionIdCacheService.class
package cn.xxxxx.rest.user.service.cache.user;
import cn.xxxxx.rest.user.service.cache.CacheService;
import cn.xxxxx.service.user.zax.feign.bo.UserBO;
import cn.xxxxx.service.user.zax.feign.client.UserFeignClient;
import cn.xxxxx.service.user.zax.feign.dto.UnionIdDTO;
import cn.xxxxx.util.common.result.JsonResult;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RBucket;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.stereotype.Component;
import java.util.concurrent.TimeUnit;
/**
* @author ITwolf
* @version 1.0
* @date 2022/01/27 15:00
*/
@Component
@Slf4j
@RefreshScope
public class UserByUnionIdCacheService implements CacheService<String, UserBO>, IRefreshUserCache {
@Autowired
private UserFeignClient userFeignClient;
@Autowired
private RedissonClient redissonClient;
// 缓存前缀
public static final String CACHE_PREFIX = "userByUnionIdCache:";
// 分隔符
private static final String SPLIT = ":";
/**
* 缓存时间:秒
*/
@Value("${user.cache.userByUnionIdCache.live.time:1800}")
private Long liveTime;
@Override
public String getCacheName() {
return CACHE_PREFIX;
}
@Override
public String buildCacheKey(String dto) {
StringBuffer key = new StringBuffer(CACHE_PREFIX);
key.append(dto);
return key.toString();
}
/**
* 10:12 2022/01/27
* 根据unionId查询店铺信息和店铺头像缓存
*
* @param dto unionId
* @return cn.xxxxx.service.user.zax.feign.bo.OrganizationAndImageBO
*/
@Override
public UserBO get(String dto) {
RBucket<UserBO> bucket = redissonClient.getBucket(buildCacheKey(dto));
return bucket.get();
}
/**
* 获取或者加载缓存
* 16:20 2020/10/9
*
* @param dto unionId
* @return cn.xxxxx.service.user.zax.feign.bo.UserBO
*/
@Override
public UserBO getOrLoad(String dto) {
RBucket<UserBO> bucket = redissonClient.getBucket(buildCacheKey(dto));
UserBO bo = bucket.get();
if (null == bo) {
return this.reload(dto);
}
return bo;
}
/**
* 设置缓存
* 10:12 2022/01/27
*
* @param dto unionId
* @param bo 用户信息
* @return cn.xxxxx.service.user.zax.feign.bo.UserBO
*/
@Override
public UserBO put(String dto, UserBO bo) {
RBucket<UserBO> bucket = redissonClient.getBucket(buildCacheKey(dto));
bucket.set(bo, liveTime, TimeUnit.SECONDS);
log.debug("[put][UserBO] key={}, value={}, liveTime={}", this.buildCacheKey(dto), bo, liveTime);
return bo;
}
/**
* 更新用户对象
* 10:12 2022/01/27
*
* @param dto unionId
* @return cn.xxxxx.service.user.zax.feign.bo.UserBO
*/
@Override
public UserBO reload(String dto) {
UserBO bo;
JsonResult<UserBO> userBOJsonResult = userFeignClient.getByUnionId(new UnionIdDTO().setUnionId(dto));
bo = userBOJsonResult.getDataSuc();
if (null != bo) {
return this.put(dto, bo);
}
return null;
}
/**
* 删除缓存
* 10:12 2022/01/27
*
* @param dto unionId
*/
@Override
public void evict(String dto) {
RBucket<String> bucket = redissonClient.getBucket(buildCacheKey(dto));
boolean rslt = bucket.delete();
log.info("[evict][UserBO] key={}, result={}", this.buildCacheKey(dto), rslt);
}
/**
* 判断缓存是否存在
* 10:12 2022/01/27
*
* @param dto unionId
* @return boolean
*/
@Override
public boolean isExists(String dto) {
RBucket<String> bucket = redissonClient.getBucket(buildCacheKey(dto));
return bucket.isExists();
}
}