方式一
添加依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-redis</artifactId>
</dependency>
添加配置文件
spring.redis.host=127.0.0.1
spring.redis.port=6379
spring.redis.pool.max-active=5 #最大连接池
代码中使用
@Autowired
private StringRedisTemplate redisTemplate;
方式二
引用依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!-- 高版本redis的lettuce需要commons-pool2 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
</dependency>
配置类
//# 自定义缓存喷子
//pingruan:
// base:
// cache-redis-ttl: -1
//
//spring:
// application:
// name: vander-springboot-demo
// redis:
// timeout: 6000ms
// password:
// port: 6379
// database: 0
// host: 192.168.164.100
// lettuce:
// pool:
// max-active: 1000 # 连接池最大连接数(使用负值表示没有限制)
// max-idle: 10 # 连接池中的最大空闲连接
// min-idle: 5 # 连接池中的最小空闲连接
// max-wait: -1 # 连接池最大阻塞等待时间(使用负值表示没有限制)
//缓存业务数据步骤:
//1、缓存
//@Cacheable(value = "project_user",key = "'id_' + #id")
//2、删除
//@CacheEvict(value="project_user",key="'id_' + #id")
//3、修改
//@CachePut(value="project_user",key="'id_' + #id")
//备注:
//#user.id 获取方法user对象的id值
//指定方法唯一数据缓存,方式一:
//@Cacheable(value = "project_cache",keyGenerator="keyGenerator")
//指定方法唯一数据缓存(可以指定过期时间s),方式二:
//@VCacheable(expireTime=60)
@Configuration
@EnableCaching // 开启缓存支持
@AutoConfigureAfter(RedisAutoConfiguration.class)
@SuppressWarnings("all")
public class RedisConfig extends CachingConfigurerSupport {
@Autowired
private BProperties bProperties;
@Bean
public RedisTemplate<String, Object> redisTemplate(LettuceConnectionFactory factory) {
RedisTemplate<String, Object> template = new RedisTemplate<>();
RedisSerializer<String> redisSerializer = new StringRedisSerializer();
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.setConnectionFactory(factory);
// key序列化方式
template.setKeySerializer(redisSerializer);
// value序列化
template.setValueSerializer(jackson2JsonRedisSerializer);
// value hashmap序列化
template.setHashValueSerializer(jackson2JsonRedisSerializer);
return template;
}
@Bean
public ValueOperations<String, Object> valueOperations(RedisTemplate<String, Object> redisTemplate){
ValueOperations<String, Object> opsForValue =redisTemplate.opsForValue();
return opsForValue;
}
//缓存管理器
@Bean
public CacheManager cacheManager(LettuceConnectionFactory factory) {
RedisSerializer<String> redisSerializer = new StringRedisSerializer();
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);
// 配置序列化(解决乱码的问题),过期时间30秒
RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig().entryTtl(Duration.ofSeconds(bProperties.getCacheRedisTtl()))
.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(redisSerializer))
.serializeValuesWith(
RedisSerializationContext.SerializationPair.fromSerializer(jackson2JsonRedisSerializer))
.disableCachingNullValues();
RedisCacheManager cacheManager = RedisCacheManager.builder(factory).cacheDefaults(config).build();
return cacheManager;
}
/**
*
* 1、针对调用方法唯一缓存,使用该方式
* 2、该方法只是声明了key的生成策略,还未被使用,需在@Cacheable注解中指定keyGenerator
* 3、如: @Cacheable(value = "users", keyGenerator = "keyGenerator")
*/
@Bean
public KeyGenerator keyGenerator() {
return new KeyGenerator() {
@Override
public Object generate(Object target, Method method, Object... params) {
StringBuffer sb = new StringBuffer();
sb.append(target.getClass().getName());
sb.append(method.getName());
for (Object obj : params) {
sb.append(JSON.toJSONString(obj).hashCode());
}
return sb.toString();
}
};
}
}
工具类
/**
* Redis工具类
*
*
* @author vander
* @date 2018年11月28日
*/
@Component
public class RedisService {
@Autowired(required=false)
private RedisTemplate<String, Object> redisTemplate;
@Autowired(required=false)
private ValueOperations<String, Object> valueOperations;
/** 默认过期时长,单位:秒 */
public final static long DEFAULT_EXPIRE = 60 * 60 * 24;//1天
/** 不设置过期时长 */
public final static long NOT_EXPIRE = -1;
private final static Gson gson = new Gson();
public void set(String key, Object value, long expire){
try{
valueOperations.set(key, toJson(value));
if(expire != NOT_EXPIRE){
redisTemplate.expire(key, expire, TimeUnit.SECONDS);
}
}catch (Exception e){
throw new BException("Redis服务异常",500);
}
}
public void set(String key, Object value){
try{
set(key, value, DEFAULT_EXPIRE);
}catch (Exception e){
throw new BException("Redis服务异常",500);
}
}
public <T> T get(String key, Class<T> clazz, long expire) {
String value = null;
try{
value = valueOperations.get(key).toString();
if(expire != NOT_EXPIRE){
redisTemplate.expire(key, expire, TimeUnit.SECONDS);
}
}catch (Exception e){
throw new BException("Redis服务异常",500);
}
return value == null ? null : fromJson(value, clazz);
}
public <T> T get(String key, Type clazz, long expire) {
String value = null;
try{
value = valueOperations.get(key).toString();
if(expire != NOT_EXPIRE){
redisTemplate.expire(key, expire, TimeUnit.SECONDS);
}
}catch (Exception e){
throw new BException("Redis服务异常",500);
}
return value == null ? null : fromJson(value, clazz);
}
public <T> T get(String key, Class<T> clazz) {
T t;
try{
t = get(key, clazz, NOT_EXPIRE);
}catch (Exception e){
throw new BException("Redis服务异常",500);
}
return t;
}
public <T> T get(String key, Type clazz) {
T t;
try{
t = get(key, clazz, NOT_EXPIRE);
}catch (Exception e){
throw new BException("Redis服务异常",500);
}
return t;
}
public String get(String key, long expire) {
String value = null;
try{
value = valueOperations.get(key).toString();
if(expire != NOT_EXPIRE){
redisTemplate.expire(key, expire, TimeUnit.SECONDS);
}
}catch (Exception e){
throw new BException("Redis服务异常",500);
}
return value;
}
public String get(String key) {
String str = null;
try{
str = get(key, NOT_EXPIRE);
}catch (Exception e){
throw new BException("Redis服务异常",500);
}
return str;
}
public void delete(String key) {
try{
redisTemplate.delete(key);
}catch (Exception e){
throw new BException("Redis服务异常",500);
}
}
/**
* Object转成JSON数据
*/
private String toJson(Object object){
if(object instanceof Integer || object instanceof Long || object instanceof Float ||
object instanceof Double || object instanceof Boolean || object instanceof String){
return String.valueOf(object);
}
return gson.toJson(object);
}
/**
* JSON数据,转成Object
*/
private <T> T fromJson(String json, Class<T> clazz){
return gson.fromJson(json, clazz);
}
/**
* JSON数据,转成Object
*/
private <T> T fromJson(String json,Type clazz){
return gson.fromJson(json, clazz);
}
public boolean hasKey(String key) {
return redisTemplate.hasKey(key);
}
}
自定义注解缓存
/**
* 自定义缓存aop
*
* @author vander
*
*/
@Component
@Aspect
public class CacheableAspect {
@Autowired
RedisService redisService;
@Pointcut("@annotation(org.pingruan.framework.component.starter.data.redis.custom.VCacheable)")
public void annotationPointcut() {
}
@Around("annotationPointcut()")
public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
// 获得当前访问的class
Class<?> className = joinPoint.getTarget().getClass();
// 获得访问的方法名
String methodName = joinPoint.getSignature().getName();
// 得到方法的参数的类型
Class<?>[] argClass = ((MethodSignature) joinPoint.getSignature()).getParameterTypes();
Object[] args = joinPoint.getArgs();
String key = "";
long expireTime = 1800; //30分钟
// 得到访问的方法对象
Method method = className.getMethod(methodName, argClass);
Type type = method.getAnnotatedReturnType().getType();
method.setAccessible(true);
// 判断是否存在@VCacheable注解
if (method.isAnnotationPresent(VCacheable.class)) {
VCacheable annotation = method.getAnnotation(VCacheable.class);
String keys = annotation.key();
if (StringUtils.isNotBlank(keys)) {
key = keys;
} else {
key = getKey(className.getName(), methodName, args);
}
expireTime = annotation.expireTime();
}
// 获取缓存是否存在
boolean hasKey = redisService.hasKey(key);
if (hasKey) {
return redisService.get(key,type);
} else {
Object res = joinPoint.proceed();
redisService.set(key, res, expireTime);
return res;
}
}
/**
* 获取唯一key
*
* @param name
* @param methodName
* @param args
* @return
*/
private String getKey(String name, String methodName, Object[] args) {
StringBuffer sb = new StringBuffer();
sb.append(name).append(".").append(methodName);
for (Object object : args) {
sb.append(JSON.toJSONString(object).hashCode());
}
return sb.toString();
}
}
@Target({ ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
public @interface VCacheable {
String key() default "";
long expireTime() default 1800;// 30分钟
}