redis緩存與刪除SpringAOP方式,支持SpringEl表達式

【前置條件】
1.maven關鍵依賴:

<dependency>
	<groupId>org.springframework.data</groupId>
	<artifactId>spring-data-redis</artifactId>
	<version>1.7.1.RELEASE</version>
</dependency>
<dependency>
	<groupId>org.springframework</groupId>
	<artifactId>spring-expression</artifactId>
	<version>4.2.6.RELEASE</version>
</dependency>

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> T getBean(Class<T> requiredType) throws BeansException {
        return applicationContext.getBean(requiredType);
    }

    public static <T> Map<String, T> getBeansOfType(Class<T> 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<Object> {
    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配置文件:

<?xml version="1.0" encoding="utf-8" ?>
<!-- <beans xmlns="http://www.springframework.org/schema/beans" -->
<!-- xmlns:context="http://www.springframework.org/schema/context" -->
<!-- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" -->
<!-- xsi:schemaLocation="http://www.springframework.org/schema/beans -->
<!-- http://www.springframework.org/schema/beans/spring-beans-4.0.xsd -->
<!-- http://www.springframework.org/schema/context -->
<!-- http://www.springframework.org/schema/context/spring-context-4.0.xsd"> -->
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
	xmlns:tx="http://www.springframework.org/schema/tx" xmlns:aop="http://www.springframework.org/schema/aop"
	xmlns:util="http://www.springframework.org/schema/util" xmlns:mvc="http://www.springframework.org/schema/mvc"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
		http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
		http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd
		http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
		http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd">
	

	<bean id="clusterConfigurationProperties" class="com.warlock.config.ClusterConfigurationProperties">
	</bean>
	
	<bean id="oldApplicationContext" class="com.bbs.redis.util.ApplicationContextBeans" ></bean>
	<bean id="oldRedisTemplate" class="org.springframework.data.redis.core.RedisTemplate">
		<property name="keySerializer">
			<bean class="org.springframework.data.redis.serializer.StringRedisSerializer" />
		</property>
		<property name="valueSerializer">
			<bean class="com.bbs.redis.util.SerializeUtil" />
		</property>
		<property name="connectionFactory" ref="jedisConnectionFactory" />
	</bean>
	<bean id="oldStringRedisTemplate" class="org.springframework.data.redis.core.StringRedisTemplate">
		<property name="keySerializer">
			<bean class="org.springframework.data.redis.serializer.StringRedisSerializer" />
		</property>
		<property name="valueSerializer">
			<bean class="com.bbs.redis.util.SerializeUtil" />
		</property>
		<property name="connectionFactory" ref="jedisConnectionFactory" />
	</bean>
	<bean id="jedisTemplate" class="org.springframework.data.redis.core.RedisTemplate">
		<property name="keySerializer">
			<bean class="org.springframework.data.redis.serializer.StringRedisSerializer" />
		</property>
		<property name="valueSerializer">
			<bean class="org.springframework.data.redis.serializer.JdkSerializationRedisSerializer" />
		</property>
		<property name="connectionFactory" ref="jedisConnectionFactory" />
	</bean>
<!-- 	<bean id="lettuceTemplate" class="org.springframework.data.redis.core.RedisTemplate"> -->
<!-- 		<property name="keySerializer"> -->
<!-- 			<bean class="org.springframework.data.redis.serializer.StringRedisSerializer" /> -->
<!-- 		</property> -->
<!-- 		<property name="valueSerializer"> -->
<!-- 			<bean class="org.springframework.data.redis.serializer.JdkSerializationRedisSerializer" /> -->
<!-- 		</property> -->
<!-- 		<property name="connectionFactory" ref="lettuceConnectionFactory" /> -->
<!-- 	</bean> -->
	
<!-- 	<bean id="lettuceConnectionFactory" class="org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory"> -->
<!-- 		<property name="password" value="${redis.cluster.password}" /> -->
<!-- 		<property name="timeout" value="${redis.cluster.timeout}" /> -->
<!-- 		<constructor-arg ref="redisClusterConfiguration" /> -->
<!-- 	</bean> -->

	<bean id="jedisConnectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory">
		<!-- <property name="hostName" value="${redis.cache.ip}" /> -->
		<!-- <property name="port" value="${redis.cache.port}" /> -->
		<property name="usePool" value="#{conf['redis.cache.usePool']}" />
		<!-- <property name="poolConfig" ref="jedisPoolConfig" /> -->
	
		<property name="password" value="#{conf['redis.cluster.password']}" />
		<property name="timeout" value="#{conf['redis.cluster.timeout']}" />
		<constructor-arg ref="redisClusterConfiguration" />
		<constructor-arg ref="jedisPoolConfig" />
	</bean>
	
	<bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig">
		<property name="maxTotal" value="#{conf['redis.cache.pool.maxTotal']}" />
		<property name="maxIdle" value="#{conf['redis.cache.pool.maxIdle']}" />
		<property name="maxWaitMillis" value="#{conf['redis.cache.pool.maxWaitMillis']}" />
		<property name="testOnBorrow" value="#{conf['redis.cache.pool.testOnBorrow']}" />
	</bean>

<!-- 	<bean id="clusterRedisNodes1" class="org.springframework.data.redis.connection.RedisNode"> -->
<!-- 		<constructor-arg value="${redis.cluster.node1.ip}" /> -->
<!-- 		<constructor-arg value="${redis.cluster.node1.port}" type="int" /> -->
<!-- 	</bean> -->
<!-- 	<bean id="clusterRedisNodes2" class="org.springframework.data.redis.connection.RedisNode"> -->
<!-- 		<constructor-arg value="${redis.cluster.node2.ip}" /> -->
<!-- 		<constructor-arg value="${redis.cluster.node2.port}" type="int" /> -->
<!-- 	</bean> -->
<!-- 		<bean id="clusterRedisNodes3" class="org.springframework.data.redis.connection.RedisNode"> -->
<!-- 		<constructor-arg value="${redis.cluster.node3.ip}" /> -->
<!-- 		<constructor-arg value="${redis.cluster.node3.port}" type="int" /> -->
<!-- 	</bean> -->
<!-- 		<bean id="clusterRedisNodes4" class="org.springframework.data.redis.connection.RedisNode"> -->
<!-- 		<constructor-arg value="${redis.cluster.node4.ip}" /> -->
<!-- 		<constructor-arg value="${redis.cluster.node4.port}" type="int" /> -->
<!-- 	</bean> -->
<!-- 		<bean id="clusterRedisNodes5" class="org.springframework.data.redis.connection.RedisNode"> -->
<!-- 		<constructor-arg value="${redis.cluster.node5.ip}" /> -->
<!-- 		<constructor-arg value="${redis.cluster.node5.port}" type="int" /> -->
<!-- 	</bean> -->
<!-- 		<bean id="clusterRedisNodes6" class="org.springframework.data.redis.connection.RedisNode"> -->
<!-- 		<constructor-arg value="${redis.cluster.node6.ip}" /> -->
<!-- 		<constructor-arg value="${redis.cluster.node6.port}" type="int" /> -->
<!-- 	</bean> -->

	<bean id="redisClusterConfiguration" class="org.springframework.data.redis.connection.RedisClusterConfiguration">
<!-- 	spring4.X的玩法 -->
<!-- 		<property name="maxRedirects" value="3" /> -->
<!-- 		<property name="clusterNodes"> -->
<!-- 			<set> -->
<!-- 				<ref bean="clusterRedisNodes1" /> -->
<!-- 				<ref bean="clusterRedisNodes2" /> -->
<!-- 				<ref bean="clusterRedisNodes3" /> -->
<!-- 				<ref bean="clusterRedisNodes4" /> -->
<!-- 				<ref bean="clusterRedisNodes5" /> -->
<!-- 				<ref bean="clusterRedisNodes6" /> -->
<!-- 			</set> -->
<!-- 		</property> -->

<!-- 		<property name="propertySource" > -->
<!-- 			<props> -->
<!-- 				<prop key="spring.redis.cluster.nodes">10.11.24.38:7000,10.11.24.38:7001,10.11.24.38:7002,10.11.24.38:7003,10.11.24.38:7004,10.11.24.38:7005</prop> -->
<!-- 				<prop key="spring.redis.cluster.timeout">6000</prop> -->
<!-- 				<prop key="spring.redis.cluster.max-redirects">3</prop> -->
<!-- 				<prop key="spring.redis.cluster.password"></prop> -->
<!-- 			</props> -->
<!-- 		</property> -->

<!-- spring3的玩法 -->
			<constructor-arg >
				<set>
					<value>#{conf['clusterHostAndPorts[0]']}</value>
					<value>#{conf['clusterHostAndPorts[1]']}</value>
					<value>#{conf['clusterHostAndPorts[2]']}</value>
					<value>#{conf['clusterHostAndPorts[3]']}</value>
					<value>#{conf['clusterHostAndPorts[4]']}</value>
					<value>#{conf['clusterHostAndPorts[5]']}</value>
				</set>
			</constructor-arg>
			
<!-- 			<constructor-arg ref="props"/> -->

<!-- <constructor-arg> -->
<!-- <bean class="java.util.Set"> -->
<!-- 	<util:set> -->
<!-- 	<value>clusterHostAndPorts[0] = 10.11.24.38:7000</value> -->
<!-- 	<value>clusterHostAndPorts[1] = 10.11.24.38:7001</value> -->
<!-- 	<value>clusterHostAndPorts[2] = 10.11.24.38:7002</value> -->
<!-- 	<value>clusterHostAndPorts[3] = 10.11.24.38:7003</value> -->
<!-- 	<value>clusterHostAndPorts[4] = 10.11.24.38:7004</value> -->
<!-- 	<value>clusterHostAndPorts[5] = 10.11.24.38:7005</value> -->
<!-- </util:set> -->
<!-- </bean> -->
<!-- </constructor-arg> -->

<!-- <property name="clusterNodes"> -->
<!-- <util:set> -->
<!-- 	<value>clusterHostAndPorts[0] = 10.11.24.38:7000</value> -->
<!-- 	<value>clusterHostAndPorts[1] = 10.11.24.38:7001</value> -->
<!-- 	<value>clusterHostAndPorts[2] = 10.11.24.38:7002</value> -->
<!-- 	<value>clusterHostAndPorts[3] = 10.11.24.38:7003</value> -->
<!-- 	<value>clusterHostAndPorts[4] = 10.11.24.38:7004</value> -->
<!-- 	<value>clusterHostAndPorts[5] = 10.11.24.38:7005</value> -->
<!-- </util:set> -->
<!-- </property> -->
		
	</bean>
	
	<bean id="redisDBUtil" class="com.bbs.redis.util.RedisDBUtil">
	</bean>
	
	<bean id="redisCacheUtil" class="com.bbs.redis.util.RedisCacheUtil" scope="singleton">
	</bean>
</beans>

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<String, Object> 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<Object>() {
            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<Boolean>() {
            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<Long>() {
            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<String, String> 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<String, String> 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<String, Object> 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<Long>() {
            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<Long>() {
            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<Long>() {
            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<Long>() {
            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<Boolean>() {
            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<Boolean>() {
            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<Long>() {
            public Long doInRedis(RedisConnection connection) throws DataAccessException {
                long count = 0L;
                RedisSerializer<String> 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<args.length;i++){
            context.setVariable(paramNames[i],args[i]);
        }
        //組裝Key
        StringBuilder cacheKeySb = new StringBuilder(keyPrefix);
        for(String keyMember : keyMembers) {
            cacheKeySb.append(KEY_MEMBER_SPLIT);
            cacheKeySb.append(getValue(parser,context,keyMember,keyDateFormat));
        }
        return cacheKeySb.toString();
    }

    /**
     * 獲取redis 鍵
     * @param args 目標方法參數
     * @param targetMethod 目標方法
     * @param keys 緩存key
     * @param keyDateFormat 緩存key成員日期的格式
     * @return
     */
    public static List<String> 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<args.length;i++){
            context.setVariable(paramNames[i],args[i]);
        }
        //key列表爲空,返回空
        if(ArrayUtil.isEmpty(keys)){
            return null;
        }
        List<String> keyList = new ArrayList<String>();
        //循環遍歷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<String> 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<String> 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
 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章