flea-frame-cache使用之Redis接入

Redis 接入

1. 參考

flea-frame-cache使用之Redis接入 源代碼
flea-frame-cache使用之Redis接入java

2. 依賴

jedis-3.0.1.jargit

<!-- Java redis -->
<dependency>
     <groupId>redis.clients</groupId>
     <artifactId>jedis</artifactId>
     <version>3.0.1</version>
</dependency>

spring-context-4.3.18.RELEASE.jargithub

<!-- Spring相關 -->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>4.3.18.RELEASE</version>
</dependency>

spring-context-support-4.3.18.RELEASE.jarredis

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context-support</artifactId>
    <version>4.3.18.RELEASE</version>
</dependency>

3. 基礎接入

3.1 定義Flea緩存接口 --- IFleaCache

可參考筆者的這篇博文 Memcached接入,再也不贅述。算法

3.2 定義抽象Flea緩存類 --- AbstractFleaCache

可參考筆者的這篇博文 Memcached接入,再也不贅述。spring

3.3 定義Redis客戶端接口類 --- RedisClient

/**
 * <p> Redis客戶端對外接口 </p>
 *
 * @author huazie
 */
public interface RedisClient {

    /**
     * <p> 往Redis塞數據 </p>
     *
     * @param key   數據鍵
     * @param value 數據值
     * @return 狀態碼 (OK :成功)
     */
    String set(final String key, final String value);

    /**
     * <p> 往Redis賽數據(用於序列化對象) </p>
     *
     * @param key   數據鍵
     * @param value 數據值
     * @return 狀態碼 (OK :成功)
     */
    String set(final byte[] key, final byte[] value);

    /**
     * <p> 往Redis塞數據 (能夠帶失效時間) </p>
     * <p> 注意 : (單位:s)</p>
     *
     * @param key    數據鍵
     * @param value  數據值
     * @param expiry 失效時間(單位:s)
     * @return 狀態碼 (OK :成功)
     */
    String set(final String key, final String value, final int expiry);

    /**
     * <p> 往Redis塞數據 (能夠帶失效時間,用於序列化對象) </p>
     * <p> 注意 : (單位:s)</p>
     *
     * @param key    數據鍵
     * @param value  數據值
     * @param expiry 失效時間(單位:s)
     * @return 狀態碼 (OK :成功)
     */
    String set(final byte[] key, final byte[] value, final int expiry);

    /**
     * <p> 往Redis塞數據 (能夠帶失效時間) </p>
     * <p> 注意:(單位:ms) </p>
     *
     * @param key    數據鍵
     * @param value  數據值
     * @param expiry 失效時間(單位:ms)
     * @return 狀態碼 (OK :成功)
     */
    String set(final String key, final String value, final long expiry);

    /**
     * <p> 往Redis塞數據 (能夠帶失效時間,用於序列化對象) </p>
     * <p> 注意:(單位:ms) </p>
     *
     * @param key    數據鍵
     * @param value  數據值
     * @param expiry 失效時間(單位:ms)
     * @return 狀態碼 (OK :成功)
     */
    String set(final byte[] key, final byte[] value, final long expiry);

    /**
     * <p> 往Redis塞數據 (帶參數) </p>
     *
     * @param key    數據鍵
     * @param value  數據值
     * @param params 參數
     * @return 狀態碼 (OK :成功)
     */
    String set(final String key, final String value, SetParams params);

    /**
     * <p> 往Redis塞數據 (帶參數,用於序列化對象) </p>
     *
     * @param key    數據鍵
     * @param value  數據值
     * @param params 參數
     * @return 狀態碼 (OK :成功)
     */
    String set(final byte[] key, final byte[] value, SetParams params);

    /**
     * <p> 從Redis取數據 </p>
     *
     * @param key 數據鍵
     * @return 數據值
     */
    String get(final String key);

    /**
     * <p> 從Redis取數據(用於獲取序列化對象) </p>
     *
     * @param key 數據鍵
     * @return 數據值
     */
    byte[] get(final byte[] key);

    /**
     * <p> 從Redis中刪除數據 </p>
     *
     * @param key 數據鍵
     * @return 被刪除key的數量
     */
    Long del(final String key);

    /**
     * <p> 獲取數據所在的Redis服務器ip(主機地址+端口) </p>
     *
     * @param key 數據鍵
     * @return 當前數據所在的Redis服務器ip
     */
    String getLocation(final String key);

    /**
     * <p> 獲取數據所在的Redis服務器ip(主機地址+端口) </p>
     *
     * @param key 數據鍵(字節數組)
     * @return 當前數據所在的Redis服務器ip
     */
    String getLocation(final byte[] key);

    /**
     * <p> 獲取數據所在的Redis服務器主機 </p>
     *
     * @param key 數據鍵
     * @return 數據所在的Redis服務器主機
     */
    String getHost(final String key);

    /**
     * <p> 獲取數據所在的Redis服務器主機 </p>
     *
     * @param key 數據鍵(字節數組)
     * @return 數據所在的Redis服務器主機
     */
    String getHost(final byte[] key);

    /**
     * <p> 獲取數據所在的Redis服務器主機端口 </p>
     *
     * @param key 數據鍵
     * @return 數據所在的Redis服務器主機端口
     */
    Integer getPort(final String key);

    /**
     * <p> 獲取數據所在的Redis服務器主機端口 </p>
     *
     * @param key 數據鍵(字節數組)
     * @return 數據所在的Redis服務器主機端口
     */
    Integer getPort(final byte[] key);

    /**
     * <p> 獲取數據所在的客戶端類 </p>
     *
     * @param key 數據鍵
     * @return 數據所在的客戶端類
     */
    Client getClient(final String key);

    /**
     * <p> 獲取數據所在的客戶端類 </p>
     *
     * @param key 數據鍵
     * @return 數據所在的客戶端類
     */
    Client getClient(final byte[] key);

    /**
     * <p> 獲取分佈式Redis集羣客戶端鏈接池 </p>
     *
     * @return 分佈式Redis集羣客戶端鏈接池
     */
    ShardedJedisPool getJedisPool();

    /**
     * <p> 設置分佈式Redis集羣客戶端 </p>
     *
     * @param shardedJedis 分佈式Redis集羣客戶端
     */
    void setShardedJedis(ShardedJedis shardedJedis);

    /**
     * <p> 獲取分佈式Redis集羣客戶端 </p>
     *
     * @return 分佈是Redis集羣客戶端
     */
    ShardedJedis getShardedJedis();

    /**
     * <p> 獲取鏈接池名 </p>
     *
     * @return 鏈接池名
     */
    String getPoolName();

    /**
     * <p> 設置鏈接池名 </p>
     *
     * @param poolName 鏈接池名
     */
    void setPoolName(String poolName);
}

3.4 定義Redis客戶端實現類 --- FleaRedisClient

該類實現 RedisClient 接口, 其中分佈式Jedis鏈接池 ShardedJedisPool 用於獲取分佈式Jedis對象 ShardedJedisShardedJedis能夠自行根據初始化的算法,計算當前傳入的數據鍵在某一臺初始化的 Redis 服務器上,從而操做對數據的添加,查找,刪除功能。數組

/**
 * <p> Flea Redis客戶端類 </p>
 *
 * @author huazie
 */
public class FleaRedisClient implements RedisClient {

    private ShardedJedisPool shardedJedisPool; // 分佈式Jedis鏈接池

    private ShardedJedis shardedJedis; // 分佈式Jedis對象

    private String poolName; // 鏈接池名

    /**
     * <p> Redis客戶端構造方法 (默認) </p>
     */
    private FleaRedisClient() {
        this(null);
    }

    /**
     * <p> Redis客戶端構造方法(指定鏈接池名)</p>
     *
     * @param poolName 鏈接池名
     */
    private FleaRedisClient(String poolName) {
        this.poolName = poolName;
        init();
    }

    /**
     * <p> 初始化分佈式Jedis鏈接池 </p>
     */
    private void init() {
        if (StringUtils.isBlank(poolName)) {
            poolName = CommonConstants.FleaPoolConstants.DEFAULT_POOL_NAME;
            shardedJedisPool = RedisPool.getInstance().getJedisPool();
        } else {
            shardedJedisPool = RedisPool.getInstance(poolName).getJedisPool();
        }

    }

    @Override
    public String set(final String key, final String value) {
        return shardedJedis.set(key, value);
    }

    @Override
    public String set(byte[] key, byte[] value) {
        return shardedJedis.set(key, value);
    }

    @Override
    public String set(final String key, final String value, final int expiry) {
        return shardedJedis.setex(key, expiry, value);
    }

    @Override
    public String set(byte[] key, byte[] value, int expiry) {
        return shardedJedis.setex(key, expiry, value);
    }

    @Override
    public String set(String key, String value, long expiry) {
        return shardedJedis.psetex(key, expiry, value);
    }

    @Override
    public String set(byte[] key, byte[] value, long expiry) {
        return shardedJedis.psetex(key, expiry, value);
    }

    @Override
    public String set(final String key, final String value, final SetParams params) {
        return shardedJedis.set(key, value, params);
    }

    @Override
    public String set(byte[] key, byte[] value, SetParams params) {
        return shardedJedis.set(key, value, params);
    }

    @Override
    public String get(final String key) {
        return shardedJedis.get(key);
    }

    @Override
    public byte[] get(byte[] key) {
        return shardedJedis.get(key);
    }

    @Override
    public Long del(final String key) {
        return shardedJedis.del(key);
    }

    @Override
    public String getLocation(final String key) {
        return getLocationByKey(key);
    }

    @Override
    public String getLocation(byte[] key) {
        return getLocationByKey(key);
    }

    @Override
    public String getHost(final String key) {
        return getHostByKey(key);
    }

    @Override
    public String getHost(byte[] key) {
        return getHostByKey(key);
    }

    @Override
    public Integer getPort(final String key) {
        return getPortByKey(key);
    }

    @Override
    public Integer getPort(byte[] key) {
        return getPortByKey(key);
    }

    @Override
    public Client getClient(String key) {
        return getClientByKey(key);
    }

    @Override
    public Client getClient(byte[] key) {
        return getClientByKey(key);
    }

    /**
     * <p> 獲取數據所在的Redis服務器ip(主機地址+端口) </p>
     *
     * @param key 數據鍵
     * @return 當前數據所在的Redis服務器ip
     */
    private String getLocationByKey(Object key) {
        StringBuilder location = new StringBuilder();
        Client client = getClientByKey(key);
        if (ObjectUtils.isNotEmpty(client)) {
            location.append(client.getHost()).append(CommonConstants.SymbolConstants.COLON).append(client.getPort());
        }
        return location.toString();
    }

    /**
     * <p> 獲取數據所在的Redis服務器主機 </p>
     *
     * @param key 數據鍵
     * @return 數據所在的Redis服務器主機
     */
    private String getHostByKey(Object key) {
        Client client = getClientByKey(key);
        if (ObjectUtils.isNotEmpty(client)) {
            return client.getHost();
        }
        return null;
    }

    /**
     * <p> 獲取數據所在的Redis服務器主機端口 </p>
     *
     * @param key 數據鍵
     * @return 數據所在的Redis服務器主機端口
     */
    private Integer getPortByKey(Object key) {
        Client client = getClientByKey(key);
        if (ObjectUtils.isNotEmpty(client)) {
            return client.getPort();
        }
        return null;
    }

    /**
     * <p> 獲取客戶端類 </p>
     *
     * @param key 數據鍵
     * @return 客戶端類
     */
    private Client getClientByKey(Object key) {
        Client client = null;
        if (ObjectUtils.isNotEmpty(key)) {
            if (key instanceof String) {
                client = shardedJedis.getShard(key.toString()).getClient();
            } else if (key instanceof byte[]) {
                client = shardedJedis.getShard((byte[]) key).getClient();
            }
        }
        return client;
    }

    @Override
    public ShardedJedisPool getJedisPool() {
        return shardedJedisPool;
    }

    @Override
    public void setShardedJedis(ShardedJedis shardedJedis) {
        this.shardedJedis = shardedJedis;
    }

    @Override
    public ShardedJedis getShardedJedis() {
        return shardedJedis;
    }

    @Override
    public String getPoolName() {
        return poolName;
    }

    @Override
    public void setPoolName(String poolName) {
        this.poolName = poolName;
        init();
    }

    /**
     * <p> 內部建造者類 </p>
     *
     * @author huazie
     */
    static class Builder {

        private String poolName; // 鏈接池名

        /**
         * <p> 默認構造器 </p>
         */
        Builder() {
        }

        /**
         * <p> 指定鏈接池的構造器 </p>
         *
         * @param poolName 鏈接池名
         */
        Builder(String poolName) {
            this.poolName = poolName;
        }

        /**
         * <p> 構建Redis客戶端對象 </p>
         *
         * @return Redis客戶端
         */
        RedisClient build() {
            if (StringUtils.isBlank(poolName)) {
                return new FleaRedisClient();
            } else {
                return new FleaRedisClient(poolName);
            }
        }
    }
}

該類的構造函數初始化邏輯,能夠看出咱們使用了 RedisPool, 下面來介紹一下。緩存

3.5 定義Redis鏈接池 --- RedisPool

RedisPool 用於Redis相關配置信息的初始化,其中重點是獲取分佈式Jedis鏈接池 ShardedJedisPool ,該類其中一個構造方法以下:bash

/**
 * @param poolConfig 鏈接池配置信息
 * @param shards Jedis分佈式服務器列表
 * @param algo 分佈式算法
 */
public ShardedJedisPool(final GenericObjectPoolConfig poolConfig, List<JedisShardInfo> shards,
      Hashing algo)
/**
 * <p>  Flea Redis 鏈接池 </p>
 *
 * @author huazie
 */
public class RedisPool {

    private static final ConcurrentMap<String, RedisPool> redisPools = new ConcurrentHashMap<>();

    private String poolName; // 鏈接池名

    private ShardedJedisPool shardedJedisPool; // 分佈式Jedis鏈接池

    private RedisPool(String poolName) {
        this.poolName = poolName;
    }

    /**
     * <p> 獲取Redis鏈接池實例 (指定鏈接池名)</p>
     *
     * @param poolName 鏈接池名
     * @return Redis鏈接池實例對象
     */
    public static RedisPool getInstance(String poolName) {
        if (!redisPools.containsKey(poolName)) {
            synchronized (redisPools) {
                if (!redisPools.containsKey(poolName)) {
                    RedisPool redisPool = new RedisPool(poolName);
                    redisPools.putIfAbsent(poolName, redisPool);
                }
            }
        }
        return redisPools.get(poolName);
    }

    /**
     * <p> 獲取Redis鏈接池實例 (默認) </p>
     *
     * @return Redis鏈接池實例對象
     */
    public static RedisPool getInstance() {
        return getInstance(CommonConstants.FleaPoolConstants.DEFAULT_POOL_NAME);
    }

    /**
     * <p> 默認初始化 </p>
     */
    void initialize() {
        // ...省略初始化的代碼
    }

    /**
     * <p> 初始化 (非默認鏈接池) </p>
     *
     * @param cacheServerList 緩存服務器集
     * @param cacheParams     緩存參數
     * @since 1.0.0
     */
    void initialize(List<CacheServer> cacheServerList, CacheParams cacheParams) {
        // ...省略初始化的代碼
    }

    /**
     * <p> 分佈式Redis集羣客戶端鏈接池 </p>
     *
     * @return 分佈式Redis集羣客戶端鏈接池
     */
    public ShardedJedisPool getJedisPool() {
        if (ObjectUtils.isEmpty(shardedJedisPool)) {
            throw new RuntimeException("獲取分佈式Redis集羣客戶端鏈接池失敗:請先調用initialize初始化");
        }
        return shardedJedisPool;
    }

    /**
     * <p> 獲取當前鏈接池名 </p>
     *
     * @return 鏈接池名
     */
    public String getPoolName() {
        return poolName;
    }
}

3.6 Redis配置文件

flea-frame-cache讀取 redis.properties(Redis配置文件),用做初始化RedisPool服務器

# Redis配置
# Redis緩存所屬系統名
redis.systemName=FleaFrame
# Redis服務器地址
redis.server=127.0.0.1:10001,127.0.0.1:10002,127.0.0.1:10003

# Redis服務登陸密碼
redis.password=huazie123,huazie123,huazie123

# Redis服務器權重分配
redis.weight=1,1,1

# Redis客戶端socket鏈接超時時間
redis.connectionTimeout=2000

# Redis客戶端socket讀寫超時時間
redis.soTimeout=2000

# Redis分佈式hash算法
# 1 : MURMUR_HASH
# 2 : MD5
redis.hashingAlg=1

# Redis客戶端鏈接池配置
# Redis客戶端Jedis鏈接池最大鏈接數
redis.pool.maxTotal=100

# Redis客戶端Jedis鏈接池最大空閒鏈接數
redis.pool.maxIdle=10

# Redis客戶端Jedis鏈接池最小空閒鏈接數
redis.pool.minIdle=0

# Redis客戶端Jedis鏈接池獲取鏈接時的最大等待毫秒數
redis.pool.maxWaitMillis=2000

3.7 定義Redis Flea緩存類 --- RedisFleaCache

該類繼承抽象Flea緩存類 AbstractFleaCache ,其構造方法可見如須要傳入Redis客戶端 RedisClient ,相關使用下面介紹:

/**
 * <p> Redis Flea緩存類 </p>
 *
 * @author huazie
 */
public class RedisFleaCache extends AbstractFleaCache {

    private RedisClient redisClient; // Redis客戶端

    /**
     * <p> 帶參數的構造方法,初始化Redis Flea緩存類 </p>
     *
     * @param name        緩存主關鍵字
     * @param expiry      失效時長
     * @param redisClient Redis客戶端
     */
    public RedisFleaCache(String name, long expiry, RedisClient redisClient) {
        super(name, expiry);
        this.redisClient = redisClient;
        cache = CacheEnum.Redis;
    }

    @Override
    public Object getNativeValue(String key) {
        if (LOGGER.isDebugEnabled()) {
            LOGGER.debug1(new Object() {}, "KEY = {}", key);
        }
        // 反序列化
        return ObjectUtils.deserialize(redisClient.get(key.getBytes()));
    }

    @Override
    public void putNativeValue(String key, Object value, long expiry) {
        // 序列化
        if (ObjectUtils.isNotEmpty(value)) {
            byte[] valueBytes = ObjectUtils.serialize(value);
            if (expiry == CommonConstants.NumeralConstants.ZERO) {
                redisClient.set(key.getBytes(), valueBytes);
            } else {
                redisClient.set(key.getBytes(), valueBytes, (int) expiry);
            }
        }

    }

    @Override
    public void deleteNativeValue(String key) {
        redisClient.del(key);
    }

    @Override
    public String getSystemName() {
        return RedisConfig.getConfig().getSystemName();
    }
}

3.8 定義抽象Flea緩存管理類 --- AbstractFleaCacheManager

可參考筆者的這篇博文 Memcached接入,再也不贅述。

3.9 定義Redis Flea緩存管理類 --- RedisFleaCacheManager

該類繼承抽象Flea緩存管理類 AbstractFleaCacheManager,構造方法使用了Redis 客戶端代理類 RedisClientProxy 獲取Redis客戶端 RedisClient,可在 3.10 查看。newCache 方法返回的是 RedisFleaCache 的實例對象,每一類 Redis 緩存數據都對應了一個 RedisFleaCache 的實例對象。

/**
 * <p> Redis Flea緩存管理類 </p>
 *
 * @author huazie
 */
public class RedisFleaCacheManager extends AbstractFleaCacheManager {

    private RedisClient redisClient;

    /**
     * <p> 默認構造方法,初始化Redis Flea緩存管理類 </p>
     */
    public RedisFleaCacheManager() {
        // 初始化默認鏈接池
        RedisPool.getInstance().initialize();
        redisClient = RedisClientProxy.getProxyInstance();
    }

    @Override
    protected AbstractFleaCache newCache(String name, long expiry) {
        return new RedisFleaCache(name, expiry, redisClient);
    }
}

3.10 定義Redis客戶端代理類 --- RedisClientProxy

Redis 客戶端代理類 RedisClientProxygetProxyInstance() 返回 默認鏈接池的 Redis 客戶端,getProxyInstance(String poolName) 返回 指定鏈接池的 Redis 客戶端。它們返回的都是 Redis 客戶端接口類 RedisClient ,實際代理的是 Flea Redis 客戶端 FleaRedisClient

/**
 * <p> RedisClient代理類 </p>
 *
 * @author huazie
 */
public class RedisClientProxy extends FleaProxy<RedisClient> {

    private final static ConcurrentMap<String, RedisClient> redisClients = new ConcurrentHashMap<String, RedisClient>();

    /**
     * <p> 獲取RedisClient代理類 (默認)</p>
     *
     * @return RedisClient代理類
     * @since 1.0.0
     */
    public static RedisClient getProxyInstance() {
        return getProxyInstance(CacheConstants.FleaCacheConstants.DEFAUTL_POOL_NAME);
    }

    /**
     * <p> 獲取RedisClient代理類 (指定鏈接池名)</p>
     *
     * @param poolName 鏈接池名
     * @return RedisClient代理類
     */
    public static RedisClient getProxyInstance(String poolName) {
        if (!redisClients.containsKey(poolName)) {
            synchronized (redisClients) {
                if (!redisClients.containsKey(poolName)) {
                    // 新建一個Flea Redis客戶端類, 用於被代理
                    RedisClient originRedisClient;
                    if(CacheConstants.FleaCacheConstants.DEFAUTL_POOL_NAME.equals(poolName)) {
                        originRedisClient = new FleaRedisClient();
                    } else {
                        originRedisClient = new FleaRedisClient(poolName);
                    }
                    RedisClient proxyRedisClient = newProxyInstance(originRedisClient.getClass().getClassLoader(), originRedisClient.getClass().getInterfaces(), new RedisClientInvocationHandler(originRedisClient));
                    redisClients.put(poolName, proxyRedisClient);
                }
            }
        }
        return redisClients.get(poolName);
    }
}

3.11 定義Redis客戶端調用處理類 --- RedisClientInvocationHandler

該類在 RedisClientProxy 中被調用,用於處理 Flea Redis 客戶端類相應方法被代理調用先後的其餘操做,本處主要實現代理前的分佈式 Jedis 對象 ShardedJedis 的獲取,代理後的分佈式 Jedis 對象 ShardedJedis 的關閉,歸還相關資源給分佈式 Jedis 鏈接池 ShardedJedisPool

/**
 * <p> Redis客戶端調用處理類 </p>
 *
 * @author huazie
 */
public class RedisClientInvocationHandler extends FleaInvocationHandler {

    /**
     * <p> 帶參數的構造方法 </p>
     *
     * @param proxyObject 代理對象
     */
    RedisClientInvocationHandler(Object proxyObject) {
        super(proxyObject);
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

        if (ObjectUtils.isEmpty(proxyObject)) {
            throw new Exception("The proxyObject must be initialized");
        }

        if (!(proxyObject instanceof RedisClient)) {
            throw new Exception("The proxyObject must implement RedisClient interface");
        }

        RedisClient redisClient = (RedisClient) proxyObject;
        ShardedJedisPool jedisPool = redisClient.getJedisPool();
        if (ObjectUtils.isNotEmpty(jedisPool)) {
            // 從分佈式Jedis鏈接池中獲取分佈式Jedis對象,並將其初始化給Redis客戶端類中的分佈式Jedis對象
            redisClient.setShardedJedis(jedisPool.getResource());
        }
        try {
            return super.invoke(proxy, method, args);
        } finally {
            ShardedJedis shardedJedis = redisClient.getShardedJedis();
            if (ObjectUtils.isNotEmpty(shardedJedis)) {
                // 使用後,關閉鏈接
                shardedJedis.close();
            }
        }
    }
}

哇,終於Redis接入差很少要完成了,下面一塊兒開始啓動單元測試吧

3.12 Redis接入自測 --- FleaCacheTest

首先,這裏須要按照 Redis 配置文件中的地址部署相應的 Redis 服務,可參考筆者的 這篇博文

@Test
    public void testRedisFleaCache() {
        try {
            AbstractFleaCacheManager manager = FleaCacheManagerFactory.getFleaCacheManager(CacheEnum.Redis.getName());
            AbstractFleaCache cache = manager.getCache("fleaparadetail");
            LOGGER.debug("Cache={}", cache);
            //#### 1.  簡單字符串
//            cache.put("menu1", "huazie");
            cache.get("menu1");
//            cache.delete("menu1");
            cache.getCacheKey();
            LOGGER.debug(cache.getCacheName() + ">>>" + cache.getCacheDesc());
        } catch (Exception e) {
            LOGGER.error("Exception:", e);
        }
    }

4. 進階接入

4.1 定義抽象Spring緩存 --- AbstractSpringCache

可參考筆者的這篇博文 Memcached接入,再也不贅述。

4.2 定義Redis Spring緩存類 --- RedisSpringCache

該類繼承抽象 Spring 緩存 AbstractSpringCache,用於對接 Spring; 從構造方法可見,該類初始化仍是使用 Redis Flea 緩存類 RedisFleaCache

/**
 * <p> Redis Spring緩存類 </p>
 *
 * @author huazie
 */
public class RedisSpringCache extends AbstractSpringCache {

    /**
     * <p> 帶參數的構造方法,初始化Redis Spring緩存類 </p>
     *
     * @param name      緩存主關鍵字
     * @param fleaCache 具體緩存實現
     */
    public RedisSpringCache(String name, IFleaCache fleaCache) {
        super(name, fleaCache);
    }

    /**
     * <p> 帶參數的構造方法,初始化Redis Spring緩存類 </p>
     *
     * @param name        緩存主關鍵字
     * @param expiry      失效時長
     * @param redisClient Redis客戶端
     */
    public RedisSpringCache(String name, long expiry, RedisClient redisClient) {
        this(name, new RedisFleaCache(name, expiry, redisClient));
    }

}

4.3 定義抽象Spring緩存管理類 --- AbstractSpringCacheManager

可參考筆者的這篇博文 Memcached接入,再也不贅述。

4.4 定義Redis Spring緩存管理類 --- RedisSpringCacheManager

該類繼承抽象 Spring 緩存管理類 AbstractSpringCacheManager,用於對接Spring; 基本實現同 Redis Flea 緩存管理類 RedisFleaCacheManager,惟一不一樣在於 newCache 的實現。

/**
 * <p> Redis Spring緩存管理類 </p>
 *
 * @author huazie
 */
public class RedisSpringCacheManager extends AbstractSpringCacheManager {

    private RedisClient redisClient;

    /**
     * <p> 默認構造方法,初始化Redis Spring緩存管理類 </p>
     */
    public RedisSpringCacheManager() {
        // 初始化默認鏈接池
        RedisPool.getInstance().initialize();
        redisClient = RedisClientProxy.getProxyInstance();
    }

    @Override
    protected AbstractSpringCache newCache(String name, long expiry) {
        return new RedisSpringCache(name, expiry, redisClient);
    }
}

4.5 spring 配置

<!--
    配置緩存管理RedisSpringCacheManager
    配置緩存時間 configMap (key緩存對象名稱 value緩存過時時間)
-->
<bean id="redisSpringCacheManager" class="com.huazie.frame.cache.redis.RedisSpringCacheManager">
    <property name="configMap">
        <map>
            <entry key="fleaparadetail" value="86400"/>
        </map>
    </property>
</bean>

<!-- 開啓緩存 -->
<cache:annotation-driven cache-manager="redisSpringCacheManager" proxy-target-class="true"/>

4.6 緩存自測

private ApplicationContext applicationContext;

    @Before
    public void init() {
        applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
        LOGGER.debug("ApplicationContext={}", applicationContext);
    }

    @Test
    public void testRedisSpringCache() {
        try {
            AbstractSpringCacheManager manager = (RedisSpringCacheManager) applicationContext.getBean("redisSpringCacheManager");
            LOGGER.debug("RedisCacheManager={}", manager);

            AbstractSpringCache cache = manager.getCache("fleaparadetail");
            LOGGER.debug("Cache={}", cache);

            //#### 1.  簡單字符串
//          cache.put("menu1", "huazie");
//            cache.get("menu1");
//            cache.get("menu1", String.class);

            //#### 2.  簡單對象(要是能夠序列化的對象)
//          String user = new String("huazie");
//          cache.put("user", user);
//          LOGGER.debug(cache.get("user", String.class));
//            cache.get("FLEA_RES_STATE");
            cache.clear();

            //#### 3.  List塞對象
//          List<String> userList = new ArrayList<String>();
//          userList.add("huazie");
//          userList.add("lgh");
//          cache.put("user_list", userList);

//          LOGGER.debug(cache.get("user_list",userList.getClass()).toString());

        } catch (Exception e) {
            LOGGER.error("Exception:", e);
        }
    }

結語

好了, Redis 的接入工做已經所有完成了。到目前爲止,不管是Memcached的接入仍是 Redis的接入,都是單一的緩存接入,筆者的 下一篇博文 將介紹如何整合Memcached和Redis接入,以應對日益複雜的業務需求。 敬請期待!!!

相關文章
相關標籤/搜索