org.springframework.boot
spring-boot-starter-redis
1.4.4.RELEASE
org.springframework.data
spring-data-redis
1.8.1.RELEASE
redis.clients
jedis
2.9.0
package com.regs.tms.common.redis;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.regs.tms.common.redis.annotation.SpringRedisCacheManager;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.interceptor.KeyGenerator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.listener.RedisMessageListenerContainer;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import redis.clients.jedis.Protocol;
import java.lang.reflect.Method;
@Configuration
@EnableCaching// 启用缓存,这个注解很重要
@ConfigurationProperties(prefix = "spring.redis")
@Data
public class RedisCacheConfig extends CachingConfigurerSupport {
private String host;
private Integer port;
private String password;
private Integer database;
private Long expiration;
/**
* 生成key的策略
*
* @return
*/
@Bean
public KeyGenerator keyGenerator() {
return new KeyGenerator() {
@Override
public Object generate(Object target, Method method, Object... params) {
StringBuilder sb = new StringBuilder();
sb.append(target.getClass().getName());
sb.append(method.getName());
for (Object obj : params) {
sb.append(obj.toString());
}
return sb.toString();
}
};
}
/**
* 管理缓存
*
* @param redisTemplate
* @return
*/
@Bean
public CacheManager springCacheManager(RedisTemplate redisTemplate) {
RedisCacheManager rcm = new SpringRedisCacheManager(redisTemplate);
return rcm;
}
/**
* RedisTemplate配置
*
* @param factory
* @return
*/
@Bean("redisTemplate")
public RedisTemplate redisTemplate(RedisConnectionFactory factory) {
StringRedisTemplate template = new StringRedisTemplate(factory);
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
ObjectMapper om = new ObjectMapper();
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(om);
template.setValueSerializer(jackson2JsonRedisSerializer);// 如果key是String,需要配置一下StringSerializer,不然key会乱码
template.afterPropertiesSet();
return template;
}
@Bean("jedisConnectionFactory")
public JedisConnectionFactory jedisConnectionFactory() {
JedisConnectionFactory factory = new JedisConnectionFactory();
factory.setHostName(host);
factory.setPort(port);
factory.setPassword(password);
factory.setDatabase(database);
factory.setTimeout(Protocol.DEFAULT_TIMEOUT); //设置连接超时时间
return factory;
}
}
package com.regs.tms.common.redis.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.TYPE})
public @interface CacheDuration {
//Sets the expire time (in seconds).
public long duration() default 60;
}
package com.regs.tms.common.redis.annotation;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.ReflectionUtils;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import static com.google.common.collect.Sets.newHashSet;
import static org.springframework.core.annotation.AnnotationUtils.findAnnotation;
import static org.springframework.util.StringUtils.isEmpty;
/**
* Created by Souler on 2018/10/18.
* 新写了一个SpringRedisCacheManager,继承自RedisCacheManager,
* 用于对@CacheDuration解析及有效期的设置
*/
public class SpringRedisCacheManager extends RedisCacheManager implements ApplicationContextAware, InitializingBean {
private ApplicationContext applicationContext;
public SpringRedisCacheManager(RedisTemplate redisTemplate) {
super(redisTemplate);
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
@Override
public void afterPropertiesSet() {
parseCacheDuration(applicationContext);
}
private void parseCacheDuration(ApplicationContext applicationContext) {
final Map cacheExpires = new HashMap<>();
String[] beanNames = applicationContext.getBeanNamesForType(Object.class);
for (String beanName : beanNames) {
final Class clazz = applicationContext.getType(beanName);
Service service = findAnnotation(clazz, Service.class);
if (null == service) {
continue;
}
addCacheExpires(clazz, cacheExpires);
}
//设置有效期
super.setExpires(cacheExpires);
}
private void addCacheExpires(final Class clazz, final Map cacheExpires) {
ReflectionUtils.doWithMethods(clazz, new ReflectionUtils.MethodCallback() {
@Override
public void doWith(Method method) throws IllegalArgumentException, IllegalAccessException {
ReflectionUtils.makeAccessible(method);
//根据CacheDuration注解获取时间
CacheDuration cacheDuration = findCacheDuration(clazz, method);
if(cacheDuration!=null) {
Cacheable cacheable = findAnnotation(method, Cacheable.class);
CacheConfig cacheConfig = findAnnotation(clazz, CacheConfig.class);
Set cacheNames = findCacheNames(cacheConfig, cacheable);
for (String cacheName : cacheNames) {
cacheExpires.put(cacheName, cacheDuration.duration());
}
}
}
}, new ReflectionUtils.MethodFilter() {
@Override
public boolean matches(Method method) {
return null != findAnnotation(method, Cacheable.class);
}
});
}
/**
* CacheDuration标注的有效期,优先使用方法上标注的有效期
*
* @param clazz
* @param method
* @return
*/
private CacheDuration findCacheDuration(Class clazz, Method method) {
CacheDuration methodCacheDuration = findAnnotation(method, CacheDuration.class);
if (null != methodCacheDuration) {
return methodCacheDuration;
}
CacheDuration classCacheDuration = findAnnotation(clazz, CacheDuration.class);
if (null != classCacheDuration) {
return classCacheDuration;
}
return null;
}
private Set findCacheNames(CacheConfig cacheConfig, Cacheable cacheable) {
return isEmpty(cacheable.value()) ?
newHashSet(cacheConfig.cacheNames()) : newHashSet(cacheable.value());
}
}