spring-data-redis 自定义注解扩展实现时效设置

前言

spring目前在@Cacheable和@CacheEvict等注解上不支持缓存时效设置,只允许通过配置文件设置全局时效。这样就很不方便设定时间。比如系统参数和业务数据的时效是不一样的,这给程序开发造成很大的困扰。不得已,本人实现了类似Sping的三个注解。以下是具体实现。

工程下载>>>

实现

1、注解类的实现

package com.example.spring.boot.redis.annotation;

import java.lang.annotation.*;

/**
 * Author: 王俊超
 * Date: 2017-06-10 05:56
 * All Rights Reserved !!!
 */
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
public @interface RedisCacheEvict {

    /**
     * 缓存名称
     *
     * @return
     */
    String cacheName();

    /**
     * 缓存key
     *
     * @return
     */
    String key();
}
package com.example.spring.boot.redis.annotation;

import java.lang.annotation.*;
import java.util.concurrent.TimeUnit;

/**
 * Author: 王俊超
 * Date: 2017-06-10 05:56
 * All Rights Reserved !!!
 */
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
public @interface RedisCacheGet {

    /**
     * 缓存名称
     *
     * @return
     */
    String cacheName();

    /**
     * 缓存key
     *
     * @return
     */
    String key();

    /**
     * 缓存过期时间
     *
     * @return
     */
    int expire() default 0;

    /**
     * 缓存的时间单位
     *
     * @return
     */
    TimeUnit timeUnit();
}
package com.example.spring.boot.redis.annotation;

import java.lang.annotation.*;
import java.util.concurrent.TimeUnit;

/**
 * Author: 王俊超
 * Date: 2017-06-10 05:56
 * All Rights Reserved !!!
 */
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
public @interface RedisCachePut {

    /**
     * 缓存名称
     *
     * @return
     */
    String cacheName();

    /**
     * 缓存key
     *
     * @return
     */
    String key();

    /**
     * 缓存过期时间
     *
     * @return
     */
    int expire() default 0;

    /**
     * 缓存的时间单位
     *
     * @return
     */
    TimeUnit timeUnit();
}

2、切面代码实现

package com.example.spring.boot.redis.aspect;

import com.example.spring.boot.redis.annotation.RedisCacheEvict;
import com.example.spring.boot.redis.annotation.RedisCacheGet;
import com.example.spring.boot.redis.annotation.RedisCachePut;
import com.example.spring.boot.redis.common.RedisClient;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.core.LocalVariableTableParameterNameDiscoverer;
import org.springframework.core.ParameterNameDiscoverer;
import org.springframework.util.StringUtils;

import java.lang.reflect.Method;


/**
 * 缓存处理时间切面
 *
 * Author: 王俊超
 * Date: 2017-06-10 06:17
 * All Rights Reserved !!!
 */
@Aspect
public class RedisCacheAspect {
    private final static char DOT = '.';
    private final static char SHARP = '#';
    private RedisClient redisClient;

    public RedisClient getRedisClient() {
        return redisClient;
    }

    public void setRedisClient(RedisClient redisClient) {
        this.redisClient = redisClient;
    }

    /**
     * 对象入缓存
     * @param pjp
     * @param cachePut
     * @return
     * @throws Throwable
     */
    @Around("@annotation(cachePut)")
    public Object cachePut(ProceedingJoinPoint pjp, RedisCachePut cachePut) throws Throwable {
        Object keyObject = getCacheKey(pjp, cachePut.key());
        Object result = pjp.proceed();

        // 不为空才保存数据
        if (result != null && keyObject != null){
            redisClient.set(cachePut.cacheName(), keyObject, result, cachePut.expire());
        }

        return result;
    }

    /**
     * 优先从缓存中取对象
     *
     * @param pjp
     * @param cacheGet
     * @return
     * @throws Throwable
     */
    @Around("@annotation(cacheGet)")
    public Object cacheGet(ProceedingJoinPoint pjp, RedisCacheGet cacheGet) throws Throwable {
        Object keyObject = getCacheKey(pjp, cacheGet.key());
        Object result = redisClient.get(cacheGet.cacheName(), keyObject);
        // 如果从缓存中没有取到数据,就从调用方法获取数据
        if (result == null) {
            result = pjp.proceed();

            // 方法的返回值不是void类型,就要将结果入缓存
            Class clz = getAdvicedMethod(pjp).getReturnType();
            if (clz != Void.class) {
                redisClient.set(cacheGet.cacheName(), keyObject, result, cacheGet.expire());
            }
        }

        return result;
    }

    /**
     * 删除缓存
     *
     * @param pjp
     * @param cacheEvict
     * @return
     * @throws Throwable
     */
    @Around("@annotation(cacheEvict)")
    public Object cacheEvict(ProceedingJoinPoint pjp, RedisCacheEvict cacheEvict) throws Throwable {
        Object keyObject = getCacheKey(pjp, cacheEvict.key());
        redisClient.del(cacheEvict.cacheName(), keyObject);
        return pjp.proceed();
    }

    /**
     * 获取缓存的key对象
     *
     * @param pjp
     * @param key
     * @return
     * @throws Exception
     */
    private Object getCacheKey(ProceedingJoinPoint pjp, String key) throws Exception {
        // 以#开头
        if (key.length() > 0 && key.charAt(0) == SHARP) {
            // 去掉#
            key = key.substring(1);
            // 将key分割成属性和参数名,第一个“.”之前是参数名,之后是属性名称
            int dotIdx = key.indexOf(DOT);
            String argName = key;
            if (dotIdx > 0) {
                argName = key.substring(0, dotIdx);
                key = key.substring(dotIdx + 1); // 剩下的属性
            }

            // 取参数值
            Object argVal = getArg(pjp, argName);

            // 获取参数的属性值
            Object objectKey = argVal;
            if (dotIdx > 0) {
                objectKey = getObjectKey(argVal, key);
            }

            return objectKey;

        } else { // 不是以#开头的就以其值作为参数key
            return key;
        }
    }

    /**
     * 获取参数对象
     *
     * @param pjp 连接点
     * @param parameterName 参数名称
     * @return
     */
    private Object getArg(ProceedingJoinPoint pjp, String parameterName) throws NoSuchMethodException {

        Method method = getAdvicedMethod(pjp);
        ParameterNameDiscoverer parameterNameDiscoverer = new LocalVariableTableParameterNameDiscoverer();
        String[] parameterNames = parameterNameDiscoverer.getParameterNames(method);
        if (parameterNames != null) {
            int idx = 0;
            for (String name : parameterNames) {
                if (name.equals(parameterName)) {
                    return pjp.getArgs()[idx];
                }
                idx++;
            }
        }

        throw new IllegalArgumentException("no such parameter name: [" + parameterName + "] in method: " + method);
    }

    /**
     * 获取拦截的方法
     *
     * @param pjp 连接点
     * @return
     * @throws NoSuchMethodException
     */
    private Method getAdvicedMethod(ProceedingJoinPoint pjp) throws NoSuchMethodException {
        Signature sig = pjp.getSignature();
        MethodSignature msig = null;
        if (!(sig instanceof MethodSignature)) {
            throw new IllegalArgumentException("annotation can only use to method.");
        }
        msig = (MethodSignature) sig;
        Object target = pjp.getTarget();
        return target.getClass().getMethod(msig.getName(), msig.getParameterTypes());
    }

    /**
     * 获取从object上获取key所对应的属性对象
     * 例如:key: country.province.city.town
     * 就相当于调用:object.getCountry().getProvince().getCity.getTown()
     *
     * @param object
     * @param key
     * @return
     * @throws Exception
     */
    private Object getObjectKey(Object object, String key) throws Exception {
        // 如果key已经是空了就直接返回
        if (StringUtils.isEmpty(key)) {
            return object;
        }

        int dotIdx = key.indexOf(DOT);
        // 形如key=aa.bb**的情况
        if (dotIdx > 0) {
            // 取第一个属性值
            String propertyName = key.substring(0, dotIdx);
            // 取剩下的key
            key = key.substring(dotIdx + 1);

            Object property = getProperty(object, getterMethod(propertyName));
            return getObjectKey(property, key);
        } else { // key=aa
            return getProperty(object, getterMethod(key));
        }
    }

    /**
     * 获取name的getter方法名称
     *
     * @param name
     * @return
     */
    private String getterMethod(String name) {
        return "get" + Character.toUpperCase(name.charAt(0)) + name.substring(1);
    }

    /**
     * 调用obj对象上的getterMethodName
     *
     * @param obj
     * @param getterMethodName
     * @return
     * @throws Exception
     */
    private Object getProperty(Object obj, String getterMethodName) throws Exception {
        return obj.getClass().getMethod(getterMethodName).invoke(obj);
    }
}

3、工具类实现

package com.example.spring.boot.redis.common;

import com.esotericsoftware.kryo.Kryo;
import com.esotericsoftware.kryo.io.Input;
import com.esotericsoftware.kryo.io.Output;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.SerializationException;

/**
 * 序列化和反序列化工具
 *
 * Author: 王俊超
 * Date: 2017-05-31 21:43
 * All Rights Reserved !!!
 */
public class KryoRedisSerializer implements RedisSerializer {
    private Kryo kryo = new Kryo();

    @Override
    public byte[] serialize(T t) throws SerializationException {
        byte[] buffer = new byte[2048];
        Output output = new Output(buffer);
        kryo.writeClassAndObject(output, t);
        byte[] result = output.toBytes();
        output.close();
        return result;
    }

    @Override
    public T deserialize(byte[] bytes) throws SerializationException {
        Input input = new Input(bytes);
        @SuppressWarnings("unchecked")
        T t = (T) kryo.readClassAndObject(input);
        input.close();
        return t;
    }

}
package com.example.spring.boot.redis.common;

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.serializer.RedisSerializer;

import java.util.Set;


/**
 * Redis客户端实现工具
 *
 * Author: 王俊超
 * Date: 2017-06-04 19:57
 * All Rights Reserved !!!
 */

public class RedisClientImpl implements RedisClient {
    private RedisTemplate redisTemplate;
    private RedisSerializer keySerializer;
    private RedisSerializer valSerializer;


    public RedisTemplate getRedisTemplate() {
        return redisTemplate;
    }

    public void setRedisTemplate(RedisTemplate redisTemplate) {
        this.redisTemplate = redisTemplate;
    }

    public RedisSerializer getKeySerializer() {
        return keySerializer;
    }

    public void setKeySerializer(RedisSerializer keySerializer) {
        this.keySerializer = keySerializer;
    }

    public RedisSerializer getValSerializer() {
        return valSerializer;
    }

    public void setValSerializer(RedisSerializer valSerializer) {
        this.valSerializer = valSerializer;
    }

    /////////////////////////////////////

    /**
     * 获取最终的key
     *
     * @param cacheName
     * @param key
     * @return
     */
    private byte[] getRealKey(Object cacheName, Object key) {
        byte[] b1 = keySerializer.serialize(cacheName);
        byte[] b2 = keySerializer.serialize(key);
        byte[] result = new byte[b1.length + b2.length];
        System.arraycopy(b1, 0, result, 0, b1.length);
        System.arraycopy(b2, 0, result, b1.length, b2.length);
        return result;
    }

    /**
     * 获取真实key
     * @param cacheName
     * @param key
     * @return
     */
    private byte[] getRealKey(byte[] cacheName, Object key) {
        byte[] b2 = keySerializer.serialize(key);
        byte[] result = new byte[cacheName.length + b2.length];
        System.arraycopy(cacheName, 0, result, 0, cacheName.length);
        System.arraycopy(b2, 0, result, cacheName.length, b2.length);

        return result;
    }


    @Override
    public long del(Object cacheName, Object... keys) {
        return redisTemplate.execute(new RedisCallback() {
            @Override
            public Long doInRedis(RedisConnection connection) throws DataAccessException {
                byte[] b1 = keySerializer.serialize(cacheName);
                long result = 0;
                for (Object o : keys) {
                    result += connection.del(getRealKey(b1, o));
                }
                return result;
            }
        });
    }

    @Override
    public void set(byte[] key, byte[] value, long liveTime) {
        redisTemplate.execute(new RedisCallback() {
            @Override
            public Boolean doInRedis(RedisConnection connection) throws DataAccessException {
                connection.set(key, value);
                if (liveTime > 0) {
                    connection.expire(key, liveTime);
                }
                return true;
            }
        });
    }

    @Override
    public void set(Object cacheName, Object key, Object value, long liveTime) {
        this.set(getRealKey(cacheName, key), valSerializer.serialize(value), liveTime);
    }

    @Override
    public void set(Object cacheName, Object key, Object value) {
        this.set(cacheName, key, value, 0L);
    }

    @Override
    public void set(byte[] key, byte[] value) {
        this.set(key, value, 0L);
    }

    /**
     * 获取redis value (String)
     *
     * @param key
     * @return
     */

    @Override
    public  T get(byte[] key) {
        return redisTemplate.execute(new RedisCallback() {
            @Override
            public T doInRedis(RedisConnection connection) throws DataAccessException {
                byte[] result = connection.get(key);
                Object obj = null;
                if (result != null) {
                    obj = valSerializer.deserialize(result);
                }

                return (T) obj;
            }
        });
    }

    @Override
    public  T get(Object cacheName, Object key) {
        return this.get(getRealKey(cacheName, key));
    }

    @Override
    public Set keys(byte[] pattern) {
        return redisTemplate.execute(new RedisCallback() {
            @Override
            public Set doInRedis(RedisConnection connection) throws DataAccessException {
                return connection.keys(pattern);
            }
        });
    }

    @Override
    public Set keys(String pattern) {
        return this.keys(keySerializer.serialize(pattern));
    }

    @Override
    public boolean exists(byte[] key) {
        return redisTemplate.execute(new RedisCallback() {
            @Override
            public Boolean doInRedis(RedisConnection connection) throws DataAccessException {
                return connection.exists(key);
            }
        });
    }

    @Override
    public boolean exists(Object cacheName, Object key) {
        return this.exists(getRealKey(cacheName, key));
    }

    @Override
    public boolean flushDb() {
        return redisTemplate.execute(new RedisCallback() {
            @Override
            public Boolean doInRedis(RedisConnection connection) throws DataAccessException {
                connection.flushDb();
                return true;
            }
        });
    }

    @Override
    public long dbSize() {
        return redisTemplate.execute(new RedisCallback() {
            public Long doInRedis(RedisConnection connection) throws DataAccessException {
                return connection.dbSize();
            }
        });
    }

    @Override
    public String ping() {
        return redisTemplate.execute(new RedisCallback() {
            public String doInRedis(RedisConnection connection) throws DataAccessException {
                return connection.ping();
            }
        });
    }
}
 
  

4、应用配置

package com.example.spring.boot.redis;

import com.example.spring.boot.redis.aspect.RedisCacheAspect;
import com.example.spring.boot.redis.common.KryoRedisSerializer;
import com.example.spring.boot.redis.common.RedisClient;
import com.example.spring.boot.redis.common.RedisClientImpl;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.data.redis.connection.RedisClusterConfiguration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;

import java.net.UnknownHostException;
import java.util.Arrays;
import java.util.List;


/**
 * Author: 王俊超
 * Date: 2017-05-07 10:02
 * All Rights Reserved !!!
 */
@Configuration
public class AppConfig {


    /**
     * Redis连接工厂
     *
     * @return
     */
    @Primary
    @Bean("redisConnectionFactory")
    public RedisConnectionFactory redisConnectionFactory() {

        // Redis集群地址
        List clusterNodes = Arrays.asList("192.168.241.150:7110",
                "192.168.241.150:7111", "192.168.241.150:7112", "192.168.241.150:7113",
                "192.168.241.150:7114", "192.168.241.150:7115", "192.168.241.150:7116",
                "192.168.241.150:7117", "192.168.241.150:7118", "192.168.241.150:7119"
        );

        // 获取Redis集群配置信息
        RedisClusterConfiguration rcf = new RedisClusterConfiguration(clusterNodes);
        return new JedisConnectionFactory(rcf);
    }

    /**
     * 创建redis模板
     *
     * @param factory
     * @return
     * @throws UnknownHostException
     */
    @Primary
    @Bean("redisTemplate")
    public RedisTemplate redisTemplate(RedisConnectionFactory factory)
            throws UnknownHostException {
        RedisTemplate template = new RedisTemplate<>();
        template.setConnectionFactory(factory);

        // 可根据需要设置
//        // redis value使用的序列化器
//        template.setValueSerializer(new KryoRedisSerializer<>());
//        template.setHashKeySerializer(new KryoRedisSerializer<>());
//        // redis key使用的序列化器
//        template.setKeySerializer(new KryoRedisSerializer<>());
//        template.setHashValueSerializer(new KryoRedisSerializer<>());

        template.afterPropertiesSet();
        return template;
    }

    /**
     * 返回redis客户端
     *
     * @param redisTemplate
     * @return
     */
    @Bean
    public RedisClient redisClient(RedisTemplate redisTemplate) {
        RedisClientImpl redisClient = new RedisClientImpl();
        redisClient.setRedisTemplate(redisTemplate);
        KryoRedisSerializer serializer = new KryoRedisSerializer<>();
        redisClient.setKeySerializer(serializer);
        redisClient.setValSerializer(serializer);

        return redisClient;
    }

    /**
     * redis缓存的切面
     * @param redisClient
     * @return
     */
    @Bean
    public RedisCacheAspect redisCacheAspect(RedisClient redisClient) {
        RedisCacheAspect aspect = new RedisCacheAspect();
        aspect.setRedisClient(redisClient);
        return aspect;
    }
}
 
  

5、应用的启动

package com.example.spring.boot.redis;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.transaction.annotation.EnableTransactionManagement;

/**
 * Author: 王俊超
 * Date: 2017-05-07 10:04
 * All Rights Reserved !!!
 */
@SpringBootApplication
@EnableTransactionManagement
@EnableCaching
@EnableAutoConfiguration
//@EnableAspectJAutoProxy
public class AppRunner {

    public static void main(String[] args) {
        ConfigurableApplicationContext ctx = SpringApplication.run(AppRunner.class, args);
    }
}

6、配置文件

server.context-path=/redis/cache
# 开启AOP
spring.aop.auto=true

测试

1、测试数据

package com.example.spring.boot.redis.entity;

/**
 * 县
 * Author: 王俊超
 * Date: 2017-06-12 20:06
 * All Rights Reserved !!!
 */
public class City {
    private long id;
    private String name;
    private Province province;

    public City() {
    }

    public City(long id, String name, Province province) {
        this.id = id;
        this.name = name;
        this.province = province;
    }

    public long getId() {
        return id;
    }

    public void setId(long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Province getProvince() {
        return province;
    }

    public void setProvince(Province province) {
        this.province = province;
    }
}
package com.example.spring.boot.redis.entity;

/**
 * 国家
 * Author: 王俊超
 * Date: 2017-06-12 20:06
 * All Rights Reserved !!!
 */
public class Country {
    private long id;
    private String name;

    public Country() {
    }

    public Country(long id, String name) {
        this.id = id;
        this.name = name;
    }

    public long getId() {
        return id;
    }

    public void setId(long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}
package com.example.spring.boot.redis.entity;

/**
 * 省
 * Author: 王俊超
 * Date: 2017-06-12 20:06
 * All Rights Reserved !!!
 */
public class Province {
    private long id;
    private String name;
    private Country country;

    public Province() {
    }

    public Province(long id, String name, Country country) {
        this.id = id;
        this.name = name;
        this.country = country;
    }

    public long getId() {
        return id;
    }

    public void setId(long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Country getCountry() {
        return country;
    }

    public void setCountry(Country country) {
        this.country = country;
    }
}
package com.example.spring.boot.redis.entity;

/**
 * 镇
 * Author: 王俊超
 * Date: 2017-06-12 20:06
 * All Rights Reserved !!!
 */
public class Town {
    private long id;
    private String name;
    private City city;

    public Town() {
    }

    public Town(long id, String name, City city) {
        this.id = id;
        this.name = name;
        this.city = city;
    }

    public long getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public City getCity() {
        return city;
    }

    public void setCity(City city) {
        this.city = city;
    }
}
package com.example.spring.boot.redis;

import com.example.spring.boot.redis.annotation.RedisCacheEvict;
import com.example.spring.boot.redis.annotation.RedisCacheGet;
import com.example.spring.boot.redis.annotation.RedisCachePut;
import com.example.spring.boot.redis.entity.City;
import com.example.spring.boot.redis.entity.Country;
import com.example.spring.boot.redis.entity.Province;
import com.example.spring.boot.redis.entity.Town;
import org.springframework.stereotype.Component;

import java.util.concurrent.TimeUnit;

/**
 * Author: 王俊超
 * Date: 2017-06-10 06:26
 * All Rights Reserved !!!
 */
@Component
public class TestData {

    public  final static Country COUNTRY = new Country(111111, "CHINA");
    public  final static Province PROVINCE = new Province(222222, "GuangZhou", COUNTRY);
    public  final static City CITY = new City(333333, "ShenZhen", PROVINCE);
    public  final static Town TOWN = new Town(444444, "Where", CITY);

    public final static String LOCATION = "location";

    @RedisCachePut(cacheName = LOCATION, key = "#town.city.province.country.id",
            expire = 60, timeUnit = TimeUnit.SECONDS)
    public Country createCountry(Town town) {
        return town.getCity().getProvince().getCountry();
    }

    @RedisCacheGet(cacheName = LOCATION, key = "#id", expire = 60, timeUnit = TimeUnit.SECONDS)
    public Country getCountry(long id) {
        return COUNTRY;
    }

    @RedisCacheEvict(cacheName = LOCATION, key = "#id")
    public void deleteCountry(long id) {
        // 清除缓存
    }
}

2、测试用例

import com.example.spring.boot.redis.AppRunner;
import com.example.spring.boot.redis.TestData;
import com.example.spring.boot.redis.common.KryoRedisSerializer;
import com.example.spring.boot.redis.common.RedisClient;
import com.example.spring.boot.redis.entity.Country;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

/**
 * Author: 王俊超
 * Date: 2017-06-12 21:10
 * All Rights Reserved !!!
 */
@RunWith(SpringRunner.class)
@SpringBootTest( classes = AppRunner.class)
public class TestRunner {
    @Autowired
    RedisClient redisClient;

    @Autowired
    TestData testData;


    /**
     * 测试序列化,反序列化
     */
    @Test
    public void testSerialize() {
        Country c1 = testData.createCountry(TestData.TOWN);
        KryoRedisSerializer serializer = new KryoRedisSerializer<>();
        byte[] b1 = serializer.serialize(c1);
        Country c2 = (Country) serializer.deserialize(b1);
        Assert.assertNotNull(c2);
        Assert.assertEquals(c1.getId(), c2.getId());
        Assert.assertEquals(c1.getName(), c2.getName());
    }

    @Test
    public void testCachePut() {

        // 先清理缓存
        redisClient.del(TestData.LOCATION, TestData.COUNTRY.getId());
        Country c = redisClient.get(TestData.LOCATION, TestData.COUNTRY.getId());
        Assert.assertNull(c);


        // 创建一个国家
        Country c1 = testData.createCountry(TestData.TOWN);

        // 直接从缓存中取数据,说明数据已经入缓存
        Country c2 = redisClient.get(TestData.LOCATION, TestData.COUNTRY.getId());
        Assert.assertNotNull(c2);
        Assert.assertEquals(c1.getId(), c2.getId());
        Assert.assertEquals(c1.getName(), c2.getName());


    }

    @Test
    public void testCacheGet() {
        // 先清理缓存
        redisClient.del(TestData.LOCATION, TestData.COUNTRY.getId());
        Country c = redisClient.get(TestData.LOCATION, TestData.COUNTRY.getId());
        Assert.assertNull(c);

        // 取数据
        Country c1 = testData.getCountry(TestData.COUNTRY.getId());
        // 从缓存中取
        Country c2 = redisClient.get(TestData.LOCATION, TestData.COUNTRY.getId());

        Assert.assertNotNull(c2);
        Assert.assertEquals(c1.getId(), c2.getId());
        Assert.assertEquals(c1.getName(), c2.getName());
    }

    @Test
    public void testCacheEvict() {
        // 创建一个国家
        Country c = testData.createCountry(TestData.TOWN);
        redisClient.del(TestData.LOCATION, TestData.COUNTRY.getId());
        c = redisClient.get(TestData.LOCATION, TestData.COUNTRY.getId());
        Assert.assertNull(c);
    }
}
 
  

                            
                        
                    
                    
                    

你可能感兴趣的:(spring,redis,springboot,kryo-java,缓存,Spring,Boot,&,Spring,Cloud)