一,应用场景:项目启动时,需要进行初始化,初始化内容为redis缓存,目的是数据提前加载到缓存,而不是在项目中查询用到了,再去查询数据库,初始化缓存
初始化实现逻辑:清空缓存,查询数据库,初始化redis及本地缓存。
二,实现
项目中redis存储的数据类型有两种,一种是String,一种是对象类型数据
String类型数据,使用StringRedisTemplate类
对象类型数据,用RedisTemplate
为啥这样参考:
https://blog.csdn.net/notsaltedfish/article/details/75948281
我参考完之后,也没太十分明白,String类型用StringRedisTemplate就行了,原因是直接保存,直接取出来没问题,不会为null啥的
重点说一下:保存对象类型用RedisTemplate
在项目中,需要把对象先序列化为字节数据,保存起来,取的时候,取得是字节数据,再反序列化为可见的对象,(我就想为什么还要进行序列及反序列操作,不能拿过来直接用吗,可以,见下文)实现如下
存:
保存数据:
ValueOperations<String,byte[]> operations = redisTemplate.opsForValue();
operations.set(CacheKeyEnum.DOCUMENT.getKey()+apiDocument.getMethod(), ProtoStuffUtils.serialize(apiDocument));
取:
BoundValueOperations<String, byte[]> operationsGet = redisTemplate.boundValueOps(CacheKeyEnum.DOCUMENT.getKey() + apiDocument.getMethod());
if (operationsGet.get() != null) {
byte[] bytes = operationsGet.get();
apiDocument = ProtoStuffUtils.deSerialize(bytes, ApiDocument.class);
}
序列化:
/**
* 序列化,保存对象到redis
* @author lr
* @date 2019-07-30 11:40
*/
public class ProtoStuffUtils {
/**
* 序列化
* @param message
* @return
*/
public static <T> byte[] serialize(T message) {
Class<T> cls = (Class<T>) message.getClass();
LinkedBuffer linkedBuffer = LinkedBuffer.allocate();
Schema<T> schema = RuntimeSchema.getSchema(cls);
byte[] bytes = ProtostuffIOUtil.toByteArray(message,schema, linkedBuffer);
return bytes;
}
/**
* 反序列化
* @param bytes
* @return
*/
public static <T> T deSerialize(byte[] bytes,Class<T> cls) {
T message = null;
try {
message = cls.newInstance();
ProtostuffIOUtil.mergeFrom(bytes,message, RuntimeSchema.getSchema(cls));
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
return message;
}
}
三,优化
上文提到为什么还要进行序列及反序列操作,不能拿过来直接用吗,项目中这样做是因为对象本身没有实现序列化接口,我尝试了一下,对象实现序列化接口,就可以不用序列化操作,实现如下
基类添加序列化
public class ApiDocument extends BaseEntity
public class BaseEntity implements Serializable {
存:
ValueOperations<String, ApiDocument> operations = redisTemplate.opsForValue();
ApiDocument apiDocument = apiDocuments.get(0);
operations.set(CacheKeyEnum.DOCUMENT.getKey() + apiDocument.getMethod(), apiDocument);
取:
BoundValueOperations<String, ApiDocument> operationsObj = redisTemplate.boundValueOps(CacheKeyEnum.DOCUMENT.getKey() + apiDocument.getMethod());
ApiDocument apiDocument1 = operationsObj.get();
四,项目初始化代码
/**
* 初始化缓存(本地和Redis)
* @author lr
* @date 2019-07-26 16:05
*/
public class InitLocalRedisCache implements InitializingBean {
private RedisTemplate redisTemplate;
@Autowired
private StringRedisTemplate stringRedisTemplate;
@Autowired
private ApiProjectMapper apiProjectMapper;
@Autowired
private ApiDocumentMapper apiDocumentMapper;
@Autowired
private AppMapper appMapper;
public InitLocalRedisCache(RedisTemplate redisTemplate) {
this.redisTemplate = redisTemplate;
}
/**
* 设置redis key的序列化方式为字符串
* @throws Exception
*/
@Override
public void afterPropertiesSet() throws Exception {
redisTemplate.setKeySerializer(new StringRedisSerializer(StandardCharsets.UTF_8));
}
/**
* 初始化redis缓存。加载时先清空缓存
*/
public void init(){
ValueOperations<String,byte[]> operations = redisTemplate.opsForValue();
ValueOperations<String, String> valueOperations = stringRedisTemplate.opsForValue();
//1、清空缓存
clearLocalRedisCache();
//2、缓存项目服务地址
List<ApiProject> apiProjects = apiProjectMapper.selectList(null);
apiProjects.stream().forEach(apiProject -> {
valueOperations.set(CacheKeyEnum.PROJECT.getKey()+apiProject.getProjectCode(), apiProject.getProductUrl());
LocalCache.OPEN_PROJECT_URL_CACHE.put(apiProject.getProjectCode(),apiProject.getProductUrl());
});
//3、缓存接口信息(已发布)
List<ApiDocument> apiDocuments = apiDocumentMapper.selectList(new QueryWrapper<ApiDocument>()
.eq(GatewayConstant.STATUS, GatewayConstant.METHOD_PUBLISHED));
apiDocuments.stream().forEach(apiDocument -> {
operations.set(CacheKeyEnum.DOCUMENT.getKey()+apiDocument.getMethod(), ProtoStuffUtils.serialize(apiDocument));
LocalCache.OPEN_DOCUMENT_CACHE.put(apiDocument.getMethod(),apiDocument);
});
//4、缓存应用秘钥
List<OpenApp> openApps = appMapper.selectList(new QueryWrapper<OpenApp>().eq(GatewayConstant.STATUS, GatewayConstant.ENABLE));
openApps.stream().forEach(openApp -> {
valueOperations.set(CacheKeyEnum.APP.getKey()+openApp.getAppId(), openApp.getAppSecret());
LocalCache.OPEN_APP_SECRET_CACHE.put(openApp.getAppId(),openApp.getAppSecret());
});
}
/**
* 清空缓存
*/
private void clearLocalRedisCache() {
//应用秘钥缓存
Set appRedis = redisTemplate.keys(CacheKeyEnum.APP.getKey() + "*");
redisTemplate.delete(appRedis);
//项目服务地址缓存
Set projectUrls = redisTemplate.keys(CacheKeyEnum.PROJECT.getKey() + "*");
redisTemplate.delete(projectUrls);
//接口详情缓存
Set documents = redisTemplate.keys(CacheKeyEnum.DOCUMENT.getKey() + "*");
redisTemplate.delete(documents);
}
}