redis缓存与删除SpringAOP方式,支持SpringEl表达式

【前置条件】
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 {
    private static Log log = LogFactory.getLog(SerializeUtil.class);

    public SerializeUtil() {
    }

    public byte[] serialize(Object object) throws SerializationException {
        if (object == null) {
            return null;
        } else {
            ObjectOutputStream oos = null;
            ByteArrayOutputStream baos = null;

            try {
                baos = new ByteArrayOutputStream();
                oos = new ObjectOutputStream(baos);
                oos.writeObject(object);
                byte[] bytes = baos.toByteArray();
                byte[] var6 = bytes;
                return var6;
            } catch (Exception var18) {
                log.info(var18.getMessage());
            } finally {
                try {
                    if (baos != null) {
                        baos.close();
                    }
                } catch (IOException var17) {
                    log.info(var17.getMessage());
                }

                try {
                    if (oos != null) {
                        oos.close();
                    }
                } catch (IOException var16) {
                    log.info(var16.getMessage());
                }

            }

            return null;
        }
    }

    public Object deserialize(byte[] bytes) throws SerializationException {
        if (bytes == null) {
            return null;
        } else {
            ByteArrayInputStream bais = null;
            ObjectInputStream ois = null;

            try {
                bais = new ByteArrayInputStream(bytes);
                ois = new ObjectInputStream(bais);
                Object o = ois.readObject();
                Object var6 = o;
                return var6;
            } catch (Exception var18) {
                log.info(var18.getMessage());
            } finally {
                try {
                    if (ois != null) {
                        ois.close();
                    }
                } catch (IOException var17) {
                    log.info(var17.getMessage());
                }

                try {
                    if (bais != null) {
                        bais.close();
                    }
                } catch (IOException var16) {
                    log.info(var16.getMessage());
                }

            }

            return null;
        }
    }
}
 
  

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() {
            public Object execute(RedisOperations operations) throws DataAccessException {
                operations.expire(key, (long)expireSeconds, TimeUnit.SECONDS);
                return operations.opsForValue().get(key);
            }
        }) : null;
    }

    public Object getDBNew(String key, int expireSeconds) {
        return this.getDBNew(key, expireSeconds, true);
    }

    public boolean setDBString(String key, String value) {
        if (key != null && !"".equals(key.trim())) {
            if (value != null && !"".equals(value.trim())) {
                try {
                    this.stringRedisTemplate.opsForValue().set(key, value);
                    return true;
                } catch (Exception var4) {
                    var4.printStackTrace();
                    return false;
                }
            } else {
                return false;
            }
        } else {
            return false;
        }
    }

    public String getDBString(String key) {
        return this.getDBString(key, true);
    }

    public String getDBString(String key, boolean readSlave) {
        return key != null && !"".equals(key.trim()) ? (String)this.stringRedisTemplate.opsForValue().get(key) : null;
    }

    public Long getDBKeyExpire(String key, boolean readSlave) {
        if (key != null && !"".equals(key.trim())) {
            try {
                return this.redisTemplate.getExpire(key);
            } catch (Exception var4) {
                return 0L;
            }
        } else {
            return null;
        }
    }

    public Long getDBKeyExpire(String key) {
        return this.getDBKeyExpire(key, true);
    }

    public boolean deleteDBKey(String key) {
        if (key != null && !"".equals(key.trim())) {
            try {
                this.redisTemplate.delete(key);
                return true;
            } catch (Exception var3) {
                return false;
            }
        } else {
            return 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 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 boolean batchSetDBString(Map map, Integer expireSeconds) {
        if (map.isEmpty()) {
            return false;
        } else if (map.size() > 300) {
            return false;
        } else {
            Iterator var4 = map.entrySet().iterator();

            while(var4.hasNext()) {
                Entry entry = (Entry)var4.next();
                this.redisTemplate.opsForValue().set((String)entry.getKey(), entry.getValue(), (long)expireSeconds.intValue(), TimeUnit.SECONDS);
            }

            return true;
        }
    }
} 
  

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
 

你可能感兴趣的:(技术类)