实际应用中,我们会有在项目服务启动的时候就去加载一些数据或做一些事情这样的需求。
为了解决这样的问题,Spring Boot 为我们提供了一个方法,通过实现接口 CommandLineRunner 来实现。
本测试类中实现CommandLineRunner接口,通过程序在启动时,遍历所有被自定义注解CacheExpire注释的方法,获取缓存失效是时间,通过Cacheable注解获取缓存信息,最后通过 redisCacheManager进行设置
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface CacheExpire {
/*
过期时间,以秒为单位
*/
@AliasFor("value")
long expireAfter() default 0;
@AliasFor("expireAfter")
long value() default 0;
}
@Slf4j
@Component
public class CacheExpireProcessor implements CommandLineRunner {
static Map expireMap = new HashMap<>();
@Autowired
RedisCacheManager redisCacheManager;
@Override
public void run(String... args) throws Exception {
Reflections reflections = new Reflections("com.longdai", new MethodAnnotationsScanner());
Set methods = reflections.getMethodsAnnotatedWith(CacheExpire.class);
log.debug("Methods annotated with CacheExpire count is:{}", methods.size());
for (Method method : methods) {
Annotation[] annotations = method.getAnnotations();
String[] cacheNames = {};
long expireAfter = 0;
Optional cachableAnnotation = Arrays.stream(annotations).filter(annotation -> annotation instanceof Cacheable).findFirst();
Optional cacheExpireAnnotation = Arrays.stream(annotations).filter(annotation -> annotation instanceof CacheExpire).findFirst();
if (cachableAnnotation.isPresent() && cacheExpireAnnotation.isPresent()) {
Cacheable cacheable = (Cacheable) cachableAnnotation.get();
CacheExpire cacheExpire = (CacheExpire) cacheExpireAnnotation.get();
cacheNames = cacheable.value();
if (cacheNames.length == 0) {
cacheNames = cacheable.cacheNames();
}
expireAfter = cacheExpire.value();
if (expireAfter == 0) {
expireAfter = cacheExpire.expireAfter();
}
}
if (cacheNames.length > 0 && expireAfter > 0) {
log.debug("cacheNames:{}", cacheNames);
log.debug("expireAfter:{}", expireAfter);
long finalExpireAfter = expireAfter;
Stream.of(cacheNames).forEach(cacheName -> expireMap.put(cacheName, finalExpireAfter));
}
}
if (!expireMap.isEmpty()) {
redisCacheManager.setExpires(expireMap);
log.debug("redis expire map has been set!");
}
}
}
@Configuration
public class RedisConfig {
@Value("${redis.host}")
private String redisHost;
@Value("${redis.port}")
private int redisPort;
@Value("${cacheRedis.host}")
private String cacheRedisHost;
@Value("${cacheRedis.port}")
private int cacheRedisPort;
@Bean
@Primary
public RedisConnectionFactory jedisConnectionFactory() {
JedisConnectionFactory jedisConnectionFactory = new JedisConnectionFactory(jedisPoolConfig());
jedisConnectionFactory.setHostName(redisHost);
jedisConnectionFactory.setPort(redisPort);
return jedisConnectionFactory;
}
@Bean(name = "cacheConnectionFatory")
public RedisConnectionFactory cacheConnectionFatory() {
JedisConnectionFactory jedisConnectionFactory = new JedisConnectionFactory(jedisPoolConfig());
jedisConnectionFactory.setHostName(cacheRedisHost);
jedisConnectionFactory.setPort(cacheRedisPort);
return jedisConnectionFactory;
}
@SuppressWarnings("Duplicates")
@Bean
public JedisPoolConfig jedisPoolConfig() {
JedisPoolConfig poolConfig = new JedisPoolConfig();
poolConfig.setMaxTotal(100); //最大连接数
poolConfig.setMaxIdle(50); //最大空闲数
poolConfig.setMaxWaitMillis(1000); //最大建立链接等待时间
return poolConfig;
}
@Bean
public JedisPool jedisPool(JedisPoolConfig jedisPoolConfig) {
return new JedisPool(jedisPoolConfig, redisHost, redisPort);
}
@Bean
@Primary
public StringRedisTemplate redisTemplate(RedisConnectionFactory redisConnectionFactory) {
return new StringRedisTemplate(redisConnectionFactory);
}
@Bean(name = "cacheRedis")
public StringRedisTemplate cacheRedisTemplate(@Qualifier("cacheConnectionFatory") RedisConnectionFactory redisConnectionFactory) {
return new StringRedisTemplate(redisConnectionFactory);
}
@Bean(name = "cacheRedisForObject")
public RedisTemplate cacheRedisForObject(@Qualifier("cacheConnectionFatory") RedisConnectionFactory redisConnectionFactory) {
RedisTemplate redisTemplate = new RedisTemplate();
redisTemplate.setConnectionFactory(redisConnectionFactory);
return redisTemplate;
}
public RedisTemplate springBootRedisCache(@Qualifier("cacheConnectionFatory") RedisConnectionFactory redisConnectionFactory) {
RedisTemplate redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(redisConnectionFactory);
redisTemplate.setEnableDefaultSerializer(false);
redisTemplate.setKeySerializer(stringRedisSerializer());
redisTemplate.setValueSerializer(genericJackson2JsonRedisJsonSerializer());
redisTemplate.afterPropertiesSet();
return redisTemplate;
}
@Bean
public KeyGenerator keyGenerator() {
return (target, method, params) -> {
StringBuilder sb = new StringBuilder();
sb.append(target.getClass().getName());
sb.append("_");
sb.append(method.getName());
sb.append("_");
for (int i = 0; i < params.length; i++) {
sb.append(params[i].toString());
if (i != params.length - 1) {
sb.append("_");
}
}
return sb.toString();
};
}
@Bean
public GenericJackson2JsonRedisSerializer genericJackson2JsonRedisJsonSerializer() {
return new GenericJackson2JsonRedisSerializer();
}
@Bean
public StringRedisSerializer stringRedisSerializer() {
return new StringRedisSerializer();
}
@Bean
public RedisCacheManager cacheManager() {
RedisCacheManager redisCacheManager = new RedisCacheManager(springBootRedisCache(cacheConnectionFatory()));
redisCacheManager.setLoadRemoteCachesOnStartup(true);
redisCacheManager.setUsePrefix(true);
redisCacheManager.setCachePrefix(cacheName -> ("LONGDAI_CACHE_" + cacheName + ":").getBytes());
redisCacheManager.setExpires(CacheConstants.getExpirationMap());
return redisCacheManager;
}
@Bean(name = "srvAuthCodeBean")
public RedisTemplate srvAuthCodeBeanRedisTemplate(@Qualifier("cacheConnectionFatory") RedisConnectionFactory redisConnectionFactory) {
RedisTemplate redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(redisConnectionFactory);
redisTemplate.afterPropertiesSet();
StringRedisSerializer stringSerializer = new StringRedisSerializer();
redisTemplate.setKeySerializer(stringSerializer);
redisTemplate.setHashKeySerializer(stringSerializer);
return redisTemplate;
}
}