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) { retrn 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();
}
}