(转)使用 Spring缓存抽象 支持 EhCache 和 Redis 混合部署

背景:最近项目组在开发本地缓存,其中用到了redis和ehcache,但是在使用注解过程中发现两者会出现冲突,这里给出解决两者冲突的具体方案。

spring-ehcache.xml配置:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:cache="http://www.springframework.org/schema/cache"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
        http://www.springframework.org/schema/cache
        http://www.springframework.org/schema/cache/spring-cache-4.0.xsd">

    <description>ehcache缓存配置管理文件</description>

    <bean id="ehCacheManagerFactory"
        class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean">
        <property name="configLocation" value="classpath:ehcache/ehcache.xml" />
    </bean>

    <bean id="ehCacheCacheManager" class="org.springframework.cache.ehcache.EhCacheCacheManager">
        <property name="cacheManager" ref="ehCacheManagerFactory" />
    </bean>

</beans>

整合Ehcache和Redis的cacheManager,并注入容器:

package org.szfs.basic.middle.cache;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collection;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.Cache;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.ehcache.EhCacheCacheManager;
import org.springframework.cache.interceptor.KeyGenerator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheManager;

/**
 * 缓存集成配置类<p>
 * 
 * 该类通过向spring提供统一的{@link CacheManager}以达到集成不同缓存中间件的目的,v0.1包括redis与ehcache<br>
 * 该类重写了{@link CachingConfigurerSupport#cacheManager()}和{@link CachingConfigurerSupport#keyGenerator()}的方法
 * 
 * @author 51
 * @version $Id: SzfsCacheConfig.java, v 0.1 2018年2月5日 下午6:45:44 51 Exp $
 * 
 * @see org.springframework.cache.annotation.CachingConfigurerSupport
 */
@Configuration
@EnableCaching
public class SzfsCacheConfig extends CachingConfigurerSupport {
    /**
     * redis缓存前缀<p>
     * 用于通过缓存名前缀识别缓存中间件
     */
    private static final String          REDIS_PREFIX = "redis-";

    @Autowired(required = false)
    private volatile RedisCacheManager   redisCacheManager;

    @Autowired(required = false)
    private volatile EhCacheCacheManager ehCacheCacheManager;

    public SzfsCacheConfig() {
        super();
    }

    /**
     * 构建CacheManager的实例szfsCacheManager<p>
     * 
     * szfsCacheManager通过缓存名称<b>前缀</b>来识别缓存类型:
     * <ul>
     *   <li>"redis-": redis cache</li>
     *   <li> others : ehcache cache</li>
     * </ul>
     * 该实例是spring操作缓存所必须的,且需要保证唯一,这意味着,如果还需要Spring集成其它缓存中间件,仍然需要集成到szfsCacheManager<br>
     * 
     * @see org.springframework.cache.annotation.CachingConfigurerSupport#cacheManager()
     */
    @Bean("szfsCacheManager")
    @Override
    public CacheManager cacheManager() {
        return new CacheManager() {
            @Override
            public Collection<String> getCacheNames() {
                Collection<String> cacheNames = new ArrayList<String>();
                if (redisCacheManager != null) {
                    cacheNames.addAll(redisCacheManager.getCacheNames());
                }
                if (ehCacheCacheManager != null) {
                    cacheNames.addAll(ehCacheCacheManager.getCacheNames());
                }
                return cacheNames;
            }

            @Override
            public Cache getCache(String name) {
                if (name.startsWith(REDIS_PREFIX)) {
                    return redisCacheManager == null ? null : redisCacheManager.getCache(name);
                } else {
                    return ehCacheCacheManager == null ? null : ehCacheCacheManager.getCache(name);
                }
            }
        };
    }

    /**
     * 构建默认的键生成器
     * @see org.springframework.cache.annotation.CachingConfigurerSupport#keyGenerator()
     */
    @Bean
    @Override
    public KeyGenerator keyGenerator() {
        return new KeyGenerator() {
            @Override
            public Object generate(Object target, Method method, Object... params) {
                StringBuilder keyStrBuilder = new StringBuilder();
                keyStrBuilder.append(target.getClass().getName());
                keyStrBuilder.append(method.getName());
                for (Object _param : params) {
                    keyStrBuilder.append(_param.toString());
                }
                return keyStrBuilder.toString();
            }
        };
    }

    public RedisCacheManager getRedisCacheManager() {
        return redisCacheManager;
    }

    public void setRedisCacheManager(RedisCacheManager redisCacheManager) {
        this.redisCacheManager = redisCacheManager;
    }

    public EhCacheCacheManager getEhCacheCacheManager() {
        return ehCacheCacheManager;
    }

    public void setEhCacheCacheManager(EhCacheCacheManager ehCacheCacheManager) {
        this.ehCacheCacheManager = ehCacheCacheManager;
    }

}

redis相关配置:

<?xml version="1.0" encoding="UTF-8"?>

<!-- Spring集成redis sentinel配置,对应配置文件:redis-sentinel.properties -->

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:cache="http://www.springframework.org/schema/cache"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans 
        http://www.springframework.org/schema/beans/spring-beans.xsd 
        http://www.springframework.org/schema/cache 
        http://www.springframework.org/schema/cache/spring-cache.xsd">

    <description>Spring集成redis岗哨配置</description>

    <!--配置 jedis pool -->
    <bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig">
        <property name="maxTotal" value="${redis.sentinel.jedis.pool.maxTotal}" />
        <property name="maxIdle" value="${redis.sentinel.jedis.pool.maxIdle}" />
        <property name="minIdle" value="${redis.sentinel.jedis.pool.minIdle}" />
        <property name="numTestsPerEvictionRun"
            value="${redis.sentinel.jedis.pool.numTestsPerEvictionRun}" />
        <property name="timeBetweenEvictionRunsMillis"
            value="${redis.sentinel.jedis.pool.timeBetweenEvictionRunsMillis}" />
        <property name="minEvictableIdleTimeMillis"
            value="${redis.sentinel.jedis.pool.minEvictableIdleTimeMillis}" />
        <property name="softMinEvictableIdleTimeMillis"
            value="${redis.sentinel.jedis.pool.softMinEvictableIdleTimeMillis}" />
        <property name="maxWaitMillis" value="${redis.sentinel.jedis.pool.maxWaitMillis}" />
        <property name="testOnBorrow" value="${redis.sentinel.jedis.pool.testOnBorrow}" />
        <property name="testWhileIdle" value="${redis.sentinel.jedis.pool.testWhileIdle}" />
        <property name="blockWhenExhausted"
            value="${redis.sentinel.jedis.pool.blockWhenExhausted}" />
    </bean>

    <!-- 配置redisSentinelConfiguration -->
    <bean id="redisSentinelConfiguration"
        class="org.springframework.data.redis.connection.RedisSentinelConfiguration">
        <property name="master">
            <bean class="org.springframework.data.redis.connection.RedisNode">
                <property name="name" value="mymaster" />
            </bean>
        </property>
        <property name="sentinels">
            <set>
                <bean class="org.springframework.data.redis.connection.RedisNode">
                    <constructor-arg name="host"
                        value="${redis.sentinel.node1.host}" />
                    <constructor-arg name="port"
                        value="${redis.sentinel.node1.port}" />
                </bean>
                <bean class="org.springframework.data.redis.connection.RedisNode">
                    <constructor-arg name="host"
                        value="${redis.sentinel.node2.host}" />
                    <constructor-arg name="port"
                        value="${redis.sentinel.node2.port}" />
                </bean>
                <bean class="org.springframework.data.redis.connection.RedisNode">
                    <constructor-arg name="host"
                        value="${redis.sentinel.node3.host}" />
                    <constructor-arg name="port"
                        value="${redis.sentinel.node3.port}" />
                </bean>
            </set>
        </property>
    </bean>

    <!-- 配置JedisConnectionFactory -->
    <bean id="jedisConnectionFactory"
        class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory">
        <property name="password" value="${redis.sentinel.password}" />
        <constructor-arg ref="jedisPoolConfig" />
        <constructor-arg ref="redisSentinelConfiguration" />
    </bean>

    <!-- 配置redisTemplate -->
    <bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate">
        <property name="connectionFactory" ref="jedisConnectionFactory" />
        <!-- 支持事务 -->
        <property name="enableTransactionSupport" value="true" />
        <property name="keySerializer">
            <bean
                class="org.springframework.data.redis.serializer.StringRedisSerializer" />
        </property>
        <property name="valueSerializer">
            <bean
                class="org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer" />
        </property>
    </bean>

    <!-- 配置redisCacheManager -->
    <bean id="redisCacheManager" class="org.springframework.data.redis.cache.RedisCacheManager">
        <constructor-arg name="redisOperations" ref="redisTemplate" />
        <!-- 默认有效期,单位:秒 -->
        <property name="defaultExpiration" value="3600" />
        <!-- 多个缓存有效期,单位:秒 -->
        <property name="expires">
            <map>
                <entry key="redis-users" value="10" />
            </map>
        </property>
    </bean>

    <!-- 配置RedisLockRegistry -->
    <bean id="redisLockRegistry"
        class="org.springframework.integration.redis.util.RedisLockRegistry">
        <constructor-arg
            type="org.springframework.data.redis.connection.RedisConnectionFactory"
            ref="jedisConnectionFactory" />
        <constructor-arg type="java.lang.String" value="${redis.sentinel.registry.key}" />
    </bean>

</beans>

参考链接:http://blog.csdn.net/pmlpml/article/details/53116377

原文地址:https://www.cnblogs.com/lixuwu/p/8427029.html