1.配置文件MyCacheConfig
@Configuration
@EnableCaching //开启spring缓存
public class MyCacheConfig extends CachingConfigurerSupport {
/**
* @Description: 使用@Cacheable注解的时候会将返回的对象缓存起来,默认缓存的值是二进制的,
* 为此我们自定义序列化配置,改成JSON格式的
*/
@Bean
public RedisCacheManager redisCacheManager(RedisTemplate redisTemplate) {
RedisCacheWriter redisCacheWriter = RedisCacheWriter.nonLockingRedisCacheWriter(redisTemplate.getConnectionFactory());
RedisCacheConfiguration redisCacheConfiguration = RedisCacheConfiguration.defaultCacheConfig()
.entryTtl(Duration.ofHours(1))// 设置缓存有效期一小时
.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(redisTemplate.getValueSerializer()));
return new RedisCacheManager(redisCacheWriter, redisCacheConfiguration);
}
/**
*自己的RedisTemplate
*/
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
RedisTemplate<String, Object> template = new RedisTemplate();
template.setConnectionFactory(factory);
//序列化配置
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
ObjectMapper om = new ObjectMapper();
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
//om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);过时
om.activateDefaultTyping(LaissezFaireSubTypeValidator.instance ,
ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY);
jackson2JsonRedisSerializer.setObjectMapper(om);
//String的序列化
StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
// key采用String的序列化方式
template.setKeySerializer(stringRedisSerializer);
// hash的key也采用String的序列化方式
template.setHashKeySerializer(stringRedisSerializer);
// value序列化方式采用jackson
template.setValueSerializer(jackson2JsonRedisSerializer);
// hash的value序列化方式采用jackson
template.setHashValueSerializer(jackson2JsonRedisSerializer);
template.afterPropertiesSet();
return template;
}
@Override
public KeyGenerator keyGenerator() {
return new KeyGenerator() {
@Override
public Object generate(Object target, Method method, Object... objects) {
//1.缓冲
StringBuilder sb = new StringBuilder();
//2.类名
sb.append(target.getClass().getSimpleName());
//3.方法名
sb.append(method.getName());
//4.参数值
for (Object obj : objects) {
sb.append(obj.toString());
}
return sb.toString();
}
};
}
}
其中解决了@Cacheable注解的时候会将返回的对象缓存起来,默认缓存的值是二进制的问题
2.最主要的实现ApplicationRunner ,项目启动的时候回自动加载
import java.lang.annotation.*;
@Component
//@Slf4j
public class CacheLoader implements ApplicationRunner {
private Logger logger = LoggerFactory.getLogger(CacheLoader.class);
@Autowired
private DictService dictService;
public CacheLoader() {
logger.info("创建缓存加载器ApplicationRunner:CacheLoader");
}
@Override
public void run(ApplicationArguments args){
logger.info("CacheLoader.run()");
logger.info("预加载字典数据到缓存");
dictService.loadDictToCache();
}
}
3.使用正常逻辑三步走,清缓存,查询数据库,放入到到缓存中
@Override
public void loadDictToCache() {
// 删除所有的dict的reids的key
Set<String> keys = iDictRedisRepository.getAllKeys();
//根据key删除所有的dict的redis
iDictRedisRepository.deleteAll(keys);
// 查询出dict表中的所有行数据
List<Dict> list = this.list();
//将dict放入到redis中 ,有两大类:dict 和 pdict
iDictRedisRepository.putAllList(list);
System.out.println("loadDictToCache finish ...");
}
3.具体实现
package com.mehow.n302.userservice.repository.impl;
import com.mehow.n302.redisService.repository.IDictRedisRepository;
import com.mehow.n302.redisService.service.DictService;
import com.mehow.n302.redisServiceapis.entity.Dict;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Repository;
import java.io.Serializable;
import java.util.*;
import java.util.stream.Collectors;
@Repository
public class IDictRedisRepositoryImpl implements IDictRedisRepository {
@Autowired
private RedisTemplate<String, Object> redisTemplate;
@Override
public Set<String> getAllKeys() {
//获取所有 dict:code 和 pdict:c.k.pk: 的keys
Set<String> deleteKeys = redisTemplate.keys(DICT_LIST_KEY+"*");
return deleteKeys;
}
@Override
public Long deleteAll(Collection<String> keys) {
return redisTemplate.delete(keys);
}
@Override
public void putAllList(List<Dict> dicts) {
//value值内容 去除p_id=0的数据
List<Dict> listByCodes = dicts.stream().filter(d->!"0".equals(d.getParentId())).collect(Collectors.toList());
//根据sort排序存放到redis中
listByCodes.sort(Comparator.comparing(Dict::getCode).thenComparing(Dict::getSort));
List<Dict> dictInput = new ArrayList<>();
String searchCode = "";
for (int i=0;i<listByCodes.size();i++) {
if(i!=0 && !searchCode.equals(listByCodes.get(i).getCode())){
//不为第一个值(因为肯定不等),且code不相等 则searchCode代表dictInput里面已经放了所有的searchCode,
redisTemplate.opsForValue().set( DICT_LIST_KEY + searchCode, dictInput);
searchCode = listByCodes.get(i).getCode();
dictInput.clear();
}
dictInput.add(listByCodes.get(i));
searchCode = listByCodes.get(i).getCode();
if(i==listByCodes.size()-1){
redisTemplate.opsForValue().set( DICT_LIST_KEY + searchCode, dictInput);
}
}
}
注:具体实现可根据自己系统的业务逻辑