【前置条件】
1.maven关键依赖:
org.springframework.data
spring-data-redis
1.7.1.RELEASE
org.springframework
spring-expression
4.2.6.RELEASE
2.redis.properties文件配置:
# redis #
redis.cache.pool.maxTotal=100
redis.cache.pool.maxIdle=5
redis.cache.pool.maxWaitMillis=1000
redis.cache.pool.testOnBorrow=true
redis.cache.usePool=true
redis.cluster.password=
redis.cluster.timeout=6000
# redis cluster ip #
clusterHostAndPorts[0]=10.11.12.247:6380
clusterHostAndPorts[1]=10.11.12.247:6380
clusterHostAndPorts[2]=10.11.12.247:6380
clusterHostAndPorts[3]=10.11.12.247:6380
clusterHostAndPorts[4]=10.11.12.247:6380
clusterHostAndPorts[5]=10.11.12.247:6380
3.spring启动注入类:
package com.bbs.redis.util;
import java.util.Map;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
public class ApplicationContextBean implements ApplicationContextAware {
private static ApplicationContext applicationContext;
public ApplicationContextBeans() {
}
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
applicationContext = applicationContext;
}
public static ApplicationContext getApplicationContext() {
return applicationContext;
}
public static Object getBean(String name) throws BeansException {
return applicationContext.getBean(name);
}
public static Object getBean(String name, Class> requiredType) throws BeansException {
return applicationContext.getBean(name, requiredType);
}
public static boolean containsBean(String name) {
return applicationContext.containsBean(name);
}
public static boolean isSingleton(String name) throws NoSuchBeanDefinitionException {
return applicationContext.isSingleton(name);
}
public static Class> getType(String name) throws NoSuchBeanDefinitionException {
return applicationContext.getType(name);
}
public static String[] getAliases(String name) throws NoSuchBeanDefinitionException {
return applicationContext.getAliases(name);
}
public static T getBean(Class requiredType) throws BeansException {
return applicationContext.getBean(requiredType);
}
public static Map getBeansOfType(Class type) throws BeansException {
return applicationContext.getBeansOfType(type);
}
}
4.SerializeUtil序列化类:
package com.bbs.redis.util.SerializeUtil;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.SerializationException;
public class SerializeUtil implements RedisSerializer
5.spring-redis.xml配置文件:
#{conf['clusterHostAndPorts[0]']}
#{conf['clusterHostAndPorts[1]']}
#{conf['clusterHostAndPorts[2]']}
#{conf['clusterHostAndPorts[3]']}
#{conf['clusterHostAndPorts[4]']}
#{conf['clusterHostAndPorts[5]']}
6.RedisDBUtil类:
package com.bbs.redis.util;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.TimeUnit;
import javax.annotation.Resource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.SessionCallback;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
@Component
public class RedisDBUtil {
private static final int LOCK_EXPIRE_SECONDS = 300;
private static final int MAX_VALUE_SIZE = 1048576;
private static final int LOG_VALUE_SIZE = 51200;
@Autowired
private StringRedisTemplate stringRedisTemplate;
@Resource(
name = "oldRedisTemplate"
)
private RedisTemplate redisTemplate;
public JedisDBUtil() {
}
public static int strToInt(String key) {
if (key != null && !"".equals(key)) {
int num = 0;
for(int i = 0; i < key.length(); ++i) {
num += key.charAt(i);
}
return num;
} else {
return 0;
}
}
public boolean setDB(String key, Object value) {
try {
this.redisTemplate.opsForValue().set(key, value);
return true;
} catch (Exception var4) {
return false;
}
}
public boolean setDB(String key, Object value, Integer expireSeconds) {
if (key != null && !"".equals(key.trim())) {
if (value == null) {
return false;
} else {
try {
this.redisTemplate.opsForValue().set(key, value, (long)expireSeconds.intValue(), TimeUnit.SECONDS);
return true;
} catch (Exception var5) {
var5.printStackTrace();
return false;
}
}
} else {
return false;
}
}
public Object getDB(String key) {
return this.redisTemplate.opsForValue().get(key);
}
public Object getDB(String key, boolean readSlave) {
return this.redisTemplate.opsForValue().get(key);
}
public Object getDBNew(final String key, final int expireSeconds, boolean readSlave) {
return key != null && !"".equals(key.trim()) ? this.redisTemplate.execute(new SessionCallback
7.RedisCacheUtil类:
package com.bbs.redis.util;
import java.util.concurrent.TimeUnit;
import javax.annotation.Resource;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.stereotype.Component;
@Component
public class RedisCacheUtil {
@Autowired
private StringRedisTemplate stringRedisTemplate;
@Resource(
name = "oldRedisTemplate"
)
private RedisTemplate redisTemplate;
private static final String HESSIAN_KEY = "hessian.";
private static final int LOCK_EXPIRE_SECONDS = 300;
private static final int MAX_VALUE_SIZE = 1048576;
private static final int LOG_VALUE_SIZE = 51200;
private static final Log logger = LogFactory.getLog(JedisCacheUtil.class);
public static final int DEFAULT_EXPIRE_SECONDS = 1800;
public JedisCacheUtil() {
}
public boolean setCacheString(String key, String value) {
return this.setCacheString(key, value, Integer.valueOf(1800));
}
public boolean setCacheString(String key, String value, Integer expireSeconds) {
if (key != null && !"".equals(key.trim())) {
if (value != null && !"".equals(value.trim())) {
if (expireSeconds == null) {
return false;
} else {
try {
this.stringRedisTemplate.opsForValue().set(key, value, (long)expireSeconds.intValue(), TimeUnit.SECONDS);
return true;
} catch (Exception var5) {
var5.printStackTrace();
return false;
}
}
} else {
return false;
}
} else {
return false;
}
}
public String getCacheString(String key) {
return key != null && !"".equals(key.trim()) ? (String)this.stringRedisTemplate.opsForValue().get(key) : null;
}
public boolean setCache(String key, Object value) {
return this.setCache(key, value, Integer.valueOf(1800));
}
public boolean setCache(String key, Object value, Integer expireSeconds) {
if (key != null && !"".equals(key.trim())) {
if (expireSeconds == null) {
return false;
} else if (value == null) {
return false;
} else {
try {
this.redisTemplate.opsForValue().set(key, value, (long)expireSeconds.intValue(), TimeUnit.SECONDS);
return true;
} catch (Exception var5) {
return false;
}
}
} else {
return false;
}
}
public Object getCache(String key) {
return key != null && !"".equals(key.trim()) ? this.redisTemplate.opsForValue().get(key) : null;
}
public Long incr(final String key) {
return key != null && !"".equals(key.trim()) ? (Long)this.redisTemplate.execute(new RedisCallback() {
public Long doInRedis(RedisConnection connection) throws DataAccessException {
return connection.incr(key.getBytes());
}
}) : null;
}
public Long incrBy(String key, int step) {
return key != null && !"".equals(key.trim()) ? this.redisTemplate.opsForValue().increment(key, (long)step) : null;
}
public Long decr(final String key) {
return key != null && !"".equals(key.trim()) ? (Long)this.redisTemplate.execute(new RedisCallback() {
public Long doInRedis(RedisConnection connection) throws DataAccessException {
return connection.decr(key.getBytes());
}
}) : null;
}
public Long decrBy(final String key, final int step) {
return key != null && !"".equals(key.trim()) ? (Long)this.redisTemplate.execute(new RedisCallback() {
public Long doInRedis(RedisConnection connection) throws DataAccessException {
return connection.decrBy(key.getBytes(), (long)step);
}
}) : null;
}
/** @deprecated */
@Deprecated
public Long deleteKey(final String key) {
return key != null && !"".equals(key.trim()) ? (Long)this.redisTemplate.execute(new RedisCallback() {
public Long doInRedis(RedisConnection connection) {
connection.del(new byte[][]{key.getBytes()});
return null;
}
}, true) : 0L;
}
public Long deleteCacheStringKey(String key) {
return this.deleteKey(key);
}
/** @deprecated */
@Deprecated
public Long deleteStrToBytesKey(String key) {
return this.deleteKey(key);
}
public Long deleteCacheKey(String key) {
return this.deleteStrToBytesKey(key);
}
public Long getKeyExpire(String key) {
if (key != null && !"".equals(key.trim())) {
try {
return this.redisTemplate.getExpire(key);
} catch (Exception var3) {
return 0L;
}
} else {
return 0L;
}
}
public Long setKeyExpire(String key, int expireSeconds) {
if (key != null && !"".equals(key.trim())) {
Boolean t = this.redisTemplate.expire(key, (long)expireSeconds, TimeUnit.SECONDS);
return t.booleanValue() ? 1L : 0L;
} else {
return null;
}
}
public boolean keyExists(final String key) {
return key != null && !"".equals(key.trim()) ? ((Boolean)this.redisTemplate.execute(new RedisCallback() {
public Boolean doInRedis(RedisConnection connection) {
return connection.exists(key.getBytes());
}
})).booleanValue() : false;
}
public boolean lock(final String key, final int expireSeconds) {
return key != null && !"".equals(key.trim()) ? ((Boolean)this.redisTemplate.execute(new RedisCallback() {
public Boolean doInRedis(RedisConnection connection) throws DataAccessException {
Boolean nx = connection.setNX(key.getBytes(), String.valueOf(System.currentTimeMillis()).getBytes());
if (!nx.booleanValue()) {
try {
Thread.sleep(100L);
} catch (InterruptedException var4) {
var4.printStackTrace();
}
nx = connection.setNX(key.getBytes(), String.valueOf(System.currentTimeMillis()).getBytes());
}
if (nx.booleanValue()) {
connection.expire(key.getBytes(), (long)expireSeconds);
}
return nx;
}
})).booleanValue() : false;
}
public boolean lock(String key) {
return this.lock(key, 300);
}
public boolean unLock(String key) {
if (key != null && !"".equals(key.trim())) {
try {
this.redisTemplate.delete(key);
return true;
} catch (Exception var3) {
var3.printStackTrace();
return false;
}
} else {
return false;
}
}
public boolean watchMethodCall(String ip, long maxNum, int expireSeconds) {
return this.incrWatchKeyNew(ip, expireSeconds, maxNum);
}
private boolean incrWatchKey(final String key, final int expireSeconds, final long maxNum) {
Long res = (Long)this.redisTemplate.execute(new RedisCallback() {
public Long doInRedis(RedisConnection connection) throws DataAccessException {
long count = 0L;
RedisSerializer rs = JedisCacheUtil.this.redisTemplate.getKeySerializer();
Long ttl = connection.ttl(key.getBytes());
if (ttl.longValue() > 0L && ttl.longValue() <= (long)expireSeconds) {
String str = (String)JedisCacheUtil.this.redisTemplate.getValueSerializer().deserialize(connection.get(key.getBytes()));
if (str != null && Long.valueOf(str).longValue() < maxNum) {
count = connection.incr(rs.serialize(key)).longValue();
}
} else {
connection.set(rs.serialize(key), rs.serialize("0"));
connection.expire(rs.serialize(key), (long)expireSeconds);
count = connection.incr(rs.serialize(key)).longValue();
}
return count;
}
});
return res.longValue() != 0L && res.longValue() <= maxNum;
}
private boolean incrWatchKeyNew(String key, int expireSeconds, long maxNum) {
return maxNum > 50000L ? false : this.incrWatchKey(key, expireSeconds, maxNum);
}
}
8.SpringEl表达式工具类:
package com.bbs.aspects;
import com.bbs.common.util.ArrayUtil;
import com.bbs.common.util.DateUtil;
import com.bbs.common.util.StringUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.LocalVariableTableParameterNameDiscoverer;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
public class SpringElUtil {
private final static Logger logger = LoggerFactory.getLogger(RedisCacheUtil.class);
/** Key组成成员分隔符 */
private final static String KEY_MEMBER_SPLIT = "_";
/** Key列表分隔符 */
private final static String KEY_SPLIT = ",";
/** springEl关键字 */
private final static String SPRING_EL_KEY_WORD = "#";
/**
* 获取方法参数名称
* @param method
* @return
*/
public static String[] getParamterNames(Method method){
LocalVariableTableParameterNameDiscoverer u =
new LocalVariableTableParameterNameDiscoverer();
return u.getParameterNames(method);
}
/**
* 获取redis 键
* @param args 目标方法参数
* @param targetMethod 目标方法
* @param keyPrefix 缓存key前缀
* @param keyMembers 缓存key成员
* @param keyDateFormat 缓存key成员日期的格式
* @return
*/
public static String getCacheKey(Object[] args,Method targetMethod,String keyPrefix,String [] keyMembers,String keyDateFormat){
//创建SpringEL表达式转换器
ExpressionParser parser = new SpelExpressionParser();
//Spring
EvaluationContext context = new StandardEvaluationContext();
//获取目标方法参数名
String [] paramNames = RedisCacheUtil.getParamterNames(targetMethod);
for(int i=0;i getCacheKeys(Object[] args, Method targetMethod,String [] keys, String keyDateFormat){
//创建SpringEL表达式转换器
ExpressionParser parser = new SpelExpressionParser();
//Spring
EvaluationContext context = new StandardEvaluationContext();
//获取目标方法参数名
String [] paramNames = RedisCacheUtil.getParamterNames(targetMethod);
for(int i=0;i keyList = new ArrayList();
//循环遍历key
for(String key : keys) {
try {
String[] keyMembers = StringUtil.split(key, KEY_SPLIT);
if (ArrayUtil.isEmpty(keyMembers)) {
continue;
}
//组装key
StringBuilder cacheKeySb = new StringBuilder();
for (String keyMember : keyMembers) {
Object value = getValue(parser,context,keyMember,keyDateFormat);
if(null == value){
cacheKeySb = null;
break;
}
cacheKeySb.append(getValue(parser,context,keyMember,keyDateFormat));
cacheKeySb.append(KEY_MEMBER_SPLIT);
}
//如果cacheKeySb非空 && 大小>0
if(null != cacheKeySb && cacheKeySb.length()>0) {
//删除key
cacheKeySb.deleteCharAt(cacheKeySb.lastIndexOf(KEY_MEMBER_SPLIT));
keyList.add(cacheKeySb.toString());
}
} catch(Throwable e) {
logger.error("RedisCacheUtil.getCacheKeys("+key+"):"+e.getMessage(),e);
}
}
return keyList;
}
/**
* 获取值
* @param parser
* @param context
* @param keyMember
* @param keyDateFormat
* @return
*/
private static Object getValue(ExpressionParser parser,EvaluationContext context,String keyMember,String keyDateFormat){
if (keyMember.startsWith(SPRING_EL_KEY_WORD)) {
Expression expression = parser.parseExpression(keyMember);
Object value = expression.getValue(context);
if(null == value){
return null;
}
//如果值类型为java.util.Date,则进行格式转换
if (value instanceof java.util.Date && StringUtil.isNotBlank(keyDateFormat)) {
return DateUtil.format((java.util.Date) value, keyDateFormat);
} else {
return value;
}
}else{
return keyMember;
}
}
}
【应用场景一:springEl表达式注解缓存实践与使用】
1.RedisCache注解类:
package com.bbs.aspects;
import org.springframework.stereotype.Component;
import java.lang.annotation.*;
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface RedisCache {
/** 表示缓存key的前缀 */
String keyPrefix();
/**
表示缓存Key成员,可以由关键字或springEl表达式组成(每个成员由下划线(_)拼接而成):
#表示springEl表达式,非#表示关键字不会进行springEl解析。
*/
String [] keyMember();
/** 表示缓存中日期成员会被keyDateFormat格式转换成字符串 */
String keyDateFormat() default "";
/** 过时时间(单位秒) */
int expireSecond() default 0;
}
2.RedisCacheAspect切面类:
package com.bbs.aspects;
import com.bbs.SpringElUtil;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.LocalVariableTableParameterNameDiscoverer;
import org.springframework.stereotype.Service;
import java.lang.reflect.Method;
@Service
@Aspect
public class RedisCacheAspect {
@Autowired
private RedisCacheUtil redisCacheUtil;
private Logger logger = LoggerFactory.getLogger(RedisCacheAspect.class);
@Pointcut(value="execution(* com.bbs.service.impl..*.*(..)) && @annotation(com.bbs.aspects.RedisCache)")
public void cachePoint() {
}
@Around(value="cachePoint()")
public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
MethodSignature methodSignature = (MethodSignature)joinPoint.getSignature();
Method targetMethod = methodSignature.getMethod();
//缓存缓存枚举
RedisCache redisCache = targetMethod.getAnnotation(RedisCache.class);
String cachedKey = null;
//从缓存中获取数据
try {
cachedKey = getCacheKey(joinPoint);
//如果cacheKey非空,从缓存中获取
if(StringUtil.isNotBlank(cachedKey)) {
Object object = redisCacheUtil.getCache(cachedKey);
if (null != object) {
logger.info("data from cachedKey:"+cachedKey);
return object;
}
}
} catch(Throwable e) {
logger.error("RedisCacheAspect.around.getCache:"+e.getMessage(),e);
}
// 以改变后的参数去执行目标方法,并保存目标方法执行后的返回值
Object retVal = joinPoint.proceed(joinPoint.getArgs());
try {
//如果cacheKey空或retV为空,不添加到缓存
if(StringUtil.isBlank(cachedKey) || null == retVal) {
return retVal;
}
//如果集合为空,不缓存
if(retVal instanceof java.util.Collection && CollectionUtil.isEmpty((java.util.Collection)retVal)){
return retVal;
}
redisCacheUtil.setCache(cachedKey, retVal,redisCache.expireSecond());
logger.info("data into cachedKey:"+cachedKey);
} catch (Throwable e) {
logger.error("RedisCacheAspect.around.setCache:"+e.getMessage(),e);
}
return retVal;
}
/**
* 获取CacheKey
* @param joinPoint
* @return
*/
private String getCacheKey(ProceedingJoinPoint joinPoint){
Object[] args = joinPoint.getArgs();
MethodSignature methodSignature = (MethodSignature)joinPoint.getSignature();
Method targetMethod = methodSignature.getMethod();
//缓存缓存枚举
RedisCache redisCache = targetMethod.getAnnotation(RedisCache.class);
String keyPrefix = redisCache.keyPrefix();
String [] keyMember = redisCache.keyMember();
String keyDateFormat = redisCache.keyDateFormat();
return SpringElUtil.getCacheKey(args,targetMethod,keyPrefix,keyMember,keyDateFormat);
}
/**
* 获取方法参数名称
* @param method
* @return
*/
private String[] getParamterNames(Method method){
LocalVariableTableParameterNameDiscoverer u =
new LocalVariableTableParameterNameDiscoverer();
return u.getParameterNames(method);
}
}
3.RedisCache缓存注解使用方法:
@RedisCache(keyPrefix={"CacheUserIdType"},keyMember = {"#orderDO.userId","#orderDO.type"})
public OrderStatus saveOrder(OrderDO orderDO){
...
}
使用说明:
条件:
1)#orderDO.userId 值为1
2)##orderDO.type 值为preSale
结论:
查询结果(结果为null或空集合不会被缓存)会被缓存到对应Key中:
key1:CacheUserIdType_1_preSale
【应用场景二:springEl表达式注解缓存删除实践与使用】
1.RedisCacheDelete注解类:
package com.bbs.aspects;
import org.springframework.stereotype.Component;
import java.lang.annotation.*;
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface RedisCacheDelete {
/** 表示缓存key的前缀 */
String keyPrefix();
/**
表示缓存Key成员,可以由关键字或springEl表达式组成(每个成员由下划线(_)拼接而成):
#表示springEl表达式,非#表示关键字不会进行springEl解析
*/
String [] keyMember();
/** cachedKey:日期格式 */
String keyDateFormat() default "";
}
2.RedisCacheDeleteAspect切面类:
package com.bbs.aspects;
import com.bbs.redis.util.RedisCacheUtil;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.lang.reflect.Method;
@Service
@Aspect
public class RedisCacheDeleteAspect {
private Logger logger = LoggerFactory.getLogger(RedisCacheDeleteAspect.class);
@Autowired
private RedisCacheUtil redisCacheUtil;
@Pointcut(value="execution(* com.bbs.service.impl..*.*(..)) && @annotation(com.bbs.aspects.RedisCacheDelete)")
public void cacheDeletePoint() {
}
@After(value="cacheDeletePoint()")
public void cacheDelete(JoinPoint joinPoint) throws Throwable {
//从缓存中获取数据
try {
String cachedKey = getCacheKey(joinPoint);
//如果cacheKey非空,从缓存中获取
if(StringUtil.isNotBlank(cachedKey)) {
redisCacheUtil.deleteCacheKey(cachedKey);
logger.info("cacheDelete.deleteCacheKey.cachedKey:"+cachedKey);
}
} catch(Throwable e) {
logger.error("RedisCacheAspect.CacheDelete.deleteCacheKey:"+e.getMessage(),e);
}
}
/**
* 获取CacheKey
* @param joinPoint
* @return
*/
private String getCacheKey(JoinPoint joinPoint){
Object[] args = joinPoint.getArgs();
MethodSignature methodSignature = (MethodSignature)joinPoint.getSignature();
Method targetMethod = methodSignature.getMethod();
//缓存缓存枚举
RedisCacheDelete redisCache = targetMethod.getAnnotation(RedisCacheDelete.class);
String keyPrefix = redisCache.keyPrefix();
String [] keyMember = redisCache.keyMember();
String keyDateFormat = redisCache.keyDateFormat();
return SpringElUtil.getCacheKey(args,targetMethod,keyPrefix,keyMember,keyDateFormat);
}
}
3.RedisCacheDelete缓存注解使用方法:
@RedisCacheDelete(keyPrefix={"CacheUserIdType"},keyMember = {"#orderDO.userId","#orderDO.type"})
public OrderStatus deleteOrder(OrderDO orderDO){
...
}
使用说明:
条件:
1)#orderDO.userId 值为1
2)#orderDO.type 值为preSale
结论:
对应Key的缓存会被删除:
key1:CacheUserIdType_1_preSale
【应用场景三:springEl表达式注解缓存批量删除实践与使用】
1.RedisCachesRemove注解类:
package com.bbs.aspects;
import org.springframework.stereotype.Component;
import java.lang.annotation.*;
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface RedisCachesRemove {
/**
keys表示多个cacheKey,其中cacheKey可以由关键字或springEl表达式成员组成,成员之间用逗号进行分割.
解析后生成的key由下划线(_)拼接而成:
#表示springEl表达式,非#表示关键字不会进行springEl解析
*/
String [] keys();
/** cachedKey:日期格式 */
String keyDateFormat() default "";
}
2.RedisCachesRemoveAspect切面类:
package com.bbs.aspects;
import com.bbs.redis.util.RedisCacheUtil;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.lang.reflect.Method;
import java.util.List;
@Service
@Aspect
public class RedisCachesRemoveAspect {
private Logger logger = LoggerFactory.getLogger(RedisCachesRemoveAspect.class);
@Autowired
private RedisCacheUtil redisCacheUtil;
@Pointcut(value="execution(* com.bbs.service.impl..*.*(..)) && @annotation(com.bbs.aspects.RedisCachesRemove)")
public void cachesRemovePoint() {
}
@After(value="cachesRemovePoint()")
public void cachesRemove(JoinPoint joinPoint) throws Throwable {
//从缓存中获取数据
try {
List cachedKeyList = getCacheKeys(joinPoint);
for(String cacheKey : cachedKeyList) {
try {
//如果cacheKey非空,从缓存中获取
if (StringUtil.isNotBlank(cacheKey)) {
redisCacheUtil.deleteCacheKey(cacheKey);
logger.info("cachesRemove.deleteCacheKey.cachedKey:"+cacheKey);
}
}catch (Exception ex){
logger.error("RedisCachesRemoveAspect.cachesRemove.deleteCacheKey:"+ex.getMessage(),ex);
}
}
} catch(Throwable e) {
logger.error("RedisCachesRemoveAspect.cachesRemove.getCacheKeys:"+e.getMessage(),e);
}
}
/**
* 获取CacheKey
* @param joinPoint
* @return
*/
private List getCacheKeys(JoinPoint joinPoint){
Object[] args = joinPoint.getArgs();
MethodSignature methodSignature = (MethodSignature)joinPoint.getSignature();
Method targetMethod = methodSignature.getMethod();
//缓存缓存枚举
RedisCachesRemove redisCache = targetMethod.getAnnotation(RedisCachesRemove.class);
String [] keys = redisCache.keys();
String keyDateFormat = redisCache.keyDateFormat();
return SpringElUtil.getCacheKeys(args,targetMethod,keys,keyDateFormat);
}
}
3.RedisCachesRemove缓存注解使用方法:
@RedisCachesRemove(keys = {"CacheUserId,#orderDO.userId","CacheModuleType,#orderDO.type"})
public OrderStatus deleteOrder(OrderDO orderDO){
...
}
使用说明:
条件:
1)#orderDO.userId 值为1
2)#orderDO.type 值为preSale
结论:
对应如下两个Key的缓存会被删除:
key1:CacheUserId_1
key2:CacheType_preSale
注意:
目前已测支持springEl表达式:
参数为基本数据类型或对应类类型:#参数名
参数为类类型,参数对象的属性值:#参数名.属性名
参数为数组,参数对象位置值:#参数名[0]
参考:
https://blog.csdn.net/BinshaoNo_1/article/details/84579326