redis+spring注解方式实现配置缓存时间过期

来源:互联网 发布:推荐淘宝蓝莓苗卖家 编辑:程序博客网 时间:2024/06/05 23:04
<bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig"> 
  <!-- 最大连接数 -->
<property name="maxTotal" value="500" />
  <!-- 最大空闲连接数 -->
        <property name="maxIdle" value="30"></property> 
        <!-- 连接最小空闲时间 -->
  <property name="minEvictableIdleTimeMillis" value="300000"></property> 
  <!-- 每次释放连接的最大数目 -->
  <property name="numTestsPerEvictionRun" value="3"></property> 
  <!-- 释放连接的扫描间隔(毫秒) -->
  <property name="timeBetweenEvictionRunsMillis" value="1800000"></property>
  <!-- 连接空闲多久后释放, 当空闲时间>该值 且 空闲连接>最大空闲连接数 时直接释放 -->
<property name="softMinEvictableIdleTimeMillis" value="10000" />
<!-- 获取连接时的最大等待毫秒数,小于零:阻塞不确定的时间,默认-1 -->
<property name="maxWaitMillis" value="1500" />
<!-- 在获取连接的时候检查有效性, 默认false -->
<property name="testOnBorrow" value="true" />
<!-- 在空闲时检查有效性, 默认false -->
<property name="testWhileIdle" value="true" />
<!-- 连接耗尽时是否阻塞, false报异常,ture阻塞直到超时, 默认true -->
<property name="blockWhenExhausted" value="false" />
</bean> 
  <bean id="jedisConnectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory" destroy-method="destroy"> 
  <property name="poolConfig" ref="jedisPoolConfig"></property> 
  <property name="hostName" value="127.0.0.1"></property> 
  <property name="port" value="6379"></property> 
  <property name="timeout" value="15000"></property> 
  <property name="usePool" value="true"></property> 
  </bean> 
  <bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate"> 
  <property name="connectionFactory" ref="jedisConnectionFactory"></property> 
  <property name="keySerializer"> 
  <bean class="org.springframework.data.redis.serializer.StringRedisSerializer"/> 
  </property> 
  <property name="valueSerializer"> 
  <bean class="org.springframework.data.redis.serializer.JdkSerializationRedisSerializer"/> 
  </property> 
  </bean> 
 
  <!-- 启用缓存注解功能,这个是必须的,否则注解不会生效,另外,该注解一定要声明在spring主配置文件中才会生效 -->    
    <cache:annotation-driven cache-manager="redisCacheManager" />    
    
    <bean id="redisCacheManager" class="com.douwong.manage.test.action.ExtendedRedisCacheManager"> 
   <!-- <constructor-arg ref="redisTemplate" />
是否使用前缀 默认:是
<property name="usePrefix" value="true" />
<property name="defaultExpiration" value="3600" /> -->

<constructor-arg name="redisOperations" ref="redisTemplate"/>
        <constructor-arg name="cacheNames">
            <set>
                <value>caiya_a</value>
                <value>caiya_test</value>
                <value>sampleCache1</value>
                <value>memoryCache</value>
                <value>scanCache</value>
                <value>padIndexCache</value>
                <value>sampleCache1</value>
                <value>sampleCache1</value>
            </set>
        </constructor-arg>
        <!-- 默认缓存名字 -->
        <property name="defaultCacheName" value="caiya_a"/>
        <!-- 是否在容器启动时初始化 -->
        <property name="loadRemoteCachesOnStartup" value="true"/>
        <!-- 是否使用前缀 -->
        <property name="usePrefix" value="true"/>
        <!-- 前缀命名,仅当usePrefix为true时才生效 -->
        <property name="cachePrefix">
            <bean class="org.springframework.data.redis.cache.DefaultRedisCachePrefix">
                <constructor-arg name="delimiter" value=":"/>
            </bean>
        </property>
        <!-- 缓存名字和有效期的分隔符 -->
        <property name="separator" value="#"/>
        <!-- 默认有效期1h -->
        <property name="defaultExpiration" value="3600"/>
        <!-- 多个缓存有效期,一般的单个工程可以省略此项 -->
        <!-- <property name="expires">
            <map>
                <entry key="caiya_a" value="1800"/>
            </map>
        </property> -->

    </bean>


package com.douwong.manage.test.action;


import java.util.Collection;
import java.util.Collections;
import java.util.regex.Pattern;


import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;


import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.springframework.cache.Cache;
import org.springframework.data.redis.cache.RedisCache;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.cache.RedisCachePrefix;
import org.springframework.data.redis.core.RedisOperations;


//import lombok.extern.log4j.Log4j2;


/**
 * 扩展redis缓存管理器
 * <p>
 * 重写 RedisCacheManager createCache 方法
 * <p>
 * 在缓存名字上添加过期时间表达式 如:cachename#60*60
 * @author hbp
 */
public class ExtendedRedisCacheManager extends RedisCacheManager {



private static final Logger logger = Logger.getLogger(ExtendedRedisCacheManager.class);


    private static final ScriptEngine scriptEngine = new ScriptEngineManager().getEngineByName("JavaScript");


    private static final Pattern pattern = Pattern.compile("[+\\-*/%]");


    private String defaultCacheName;


    private char separator = '#';


    public ExtendedRedisCacheManager(RedisOperations redisOperations) {
        this(redisOperations, Collections.<String>emptyList());
    }


    public ExtendedRedisCacheManager(RedisOperations redisOperations, Collection<String> cacheNames) {
        super(redisOperations, cacheNames);
    }


    @Override
    public Cache getCache(String name) {
        // try to get cache by name
        RedisCache cache = (RedisCache) super.getCache(name);
        if (cache != null) {
            return cache;
        }


        // there's no cache which has given name
        // find separator in cache name
        int index = name.lastIndexOf(getSeparator());
        if (index < 0) {
            return null;
        }


        // split name by the separator
        String cacheName = name.substring(0, index);
        if(StringUtils.isBlank(cacheName)){
            cacheName = defaultCacheName;
        }
        cache = (RedisCache) super.getCache(cacheName);
        if (cache == null) {
            return null;
        }


        // get expiration from name
        Long expiration = getExpiration(name, index);
        if (expiration == null || expiration < 0) {
            logger.warn("Default expiration time will be used for cache '{}' because cannot parse '{}', cacheName : " + cacheName + ", name : " + name);
            return cache;
        }


        return new RedisCache(cacheName, (isUsePrefix() ? getCachePrefix().prefix(cacheName) : null), getRedisOperations(), expiration);
    }




    public char getSeparator() {
        return separator;
    }


    /**
     * Char that separates cache name and expiration time, default: #.
     *
     * @param separator
     */
    public void setSeparator(char separator) {
        this.separator = separator;
    }


    private Long getExpiration(final String name, final int separatorIndex) {
        Long expiration = null;
        String expirationAsString = name.substring(separatorIndex + 1);
        try {
            // calculate expiration, support arithmetic expressions.
            if(pattern.matcher(expirationAsString).find()){
                expiration = (long) Double.parseDouble(scriptEngine.eval(expirationAsString).toString());
            }else{
                expiration = Long.parseLong(expirationAsString);
            }
        } catch (NumberFormatException ex) {
            logger.error(String.format("Cannnot separate expiration time from cache: '%s'", name), ex);
        } catch (ScriptException e) {
            logger.error(String.format("Cannnot separate expiration time from cache: '%s'", name), e);
        }


        return expiration;
    }


    @Override
    public void setUsePrefix(boolean usePrefix) {
        super.setUsePrefix(usePrefix);
    }


    @Override
    public void setCachePrefix(RedisCachePrefix cachePrefix) {
        super.setCachePrefix(cachePrefix);
    }


    public void setDefaultCacheName(String defaultCacheName) {
        this.defaultCacheName = defaultCacheName;
    }


}


注意:在引入相关jar包的时候,必须要用jedis_2.9.0.jar、spring-data-redis-1.6.0.RELEASE.jar,因为这些jar包的版本对整个项目影响很大的;

可以参考代码来源:https://my.oschina.net/wnjustdoit/blog/644311