多级缓存架构开发 六 ( 测试开发的框架 )

0.导入pom文件

  父级模块的pom文件添加

 <dependencyManagement>
        <dependencies>

            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-test</artifactId>
                <version>${spring.boot.version}</version>
                <scope>test</scope>
            </dependency>

        </dependencies>
    </dependencyManagement>

子级模块的pom文件添加

 <dependencies>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

    </dependencies>

 

1.注册RedisTemplate客户端

         1.1)配置文件

spring.redis.pool.max-idle=200
spring.redis.pool.min-idle=10
spring.redis.pool.max-active=80
spring.redis.pool.max-wait=-1

spring.redis.database=0
#server host
spring.redis.host=127.0.0.1
#server password
spring.redis.password=
#connection port
spring.redis.port=6379

    1.2) 把redisTemplate客户端交给spring容器管理

package org.github.roger.cache.config;

import io.lettuce.core.resource.ClientResources;
import io.lettuce.core.resource.DefaultClientResources;
import org.github.roger.serializer.FastJsonRedisSerializer;
import org.github.roger.serializer.KryoRedisSerializer;
import org.github.roger.serializer.StringRedisSerializer;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.RedisPassword;
import org.springframework.data.redis.connection.RedisStandaloneConfiguration;
import org.springframework.data.redis.connection.lettuce.LettuceClientConfiguration;
import org.springframework.data.redis.connection.lettuce.LettuceClientConfiguration.LettuceClientConfigurationBuilder;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;

@Configuration
@PropertySource({"classpath:application.properties"})
public class RedisConfig {

    @Value("${spring.redis.database:0}")
    private int database;

    @Value("${spring.redis.host:127.0.0.1}")
    private String host;

    @Value("${spring.redis.password:}")
    private String password;

    @Value("${spring.redis.port:6379}")
    private int port;

    @Value("${spring.redis.pool.max-idle:200}")
    private int maxIdle;

    @Value("${spring.redis.pool.min-idle:10}")
    private int minIdle;

    @Value("${spring.redis.pool.max-active:80}")
    private int maxActive;

    @Value("${spring.redis.pool.max-wait:-1}")
    private int maxWait;


//    @Bean
//    public JedisConnectionFactory redisConnectionFactory() {
//        JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
//        jedisPoolConfig.setMinIdle(minIdle);
//        jedisPoolConfig.setMaxIdle(maxIdle);
//        jedisPoolConfig.setMaxTotal(maxActive);
//        jedisPoolConfig.setMaxWaitMillis(maxWait);
//
//        JedisConnectionFactory jedisConnectionFactory = new JedisConnectionFactory(jedisPoolConfig);
//        jedisConnectionFactory.setDatabase(database);
//        jedisConnectionFactory.setHostName(host);
//        jedisConnectionFactory.setPassword(password);
//        jedisConnectionFactory.setPort(port);
//        jedisConnectionFactory.setUsePool(true);
//        return jedisConnectionFactory;
//    }

    @Bean
    public LettuceConnectionFactory redisConnectionFactory() {
        ClientResources clientResources = DefaultClientResources.create();
        LettuceClientConfigurationBuilder builder = LettuceClientConfiguration.builder();
        builder.clientResources(clientResources);
        LettuceClientConfiguration configuration = builder.build();

        RedisStandaloneConfiguration config = new RedisStandaloneConfiguration();
        config.setHostName(host);
        config.setPort(port);
        config.setPassword(RedisPassword.of(password));
        config.setDatabase(database);
        return new LettuceConnectionFactory(config, configuration);
    }

    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
        RedisTemplate<String, Object> redisTemplate = new RedisTemplate<String, Object>();
        redisTemplate.setConnectionFactory(redisConnectionFactory);

        FastJsonRedisSerializer<Object> fastJsonRedisSerializer = new FastJsonRedisSerializer<Object>(Object.class, "com.xxx.");
        KryoRedisSerializer<Object> kryoRedisSerializer = new KryoRedisSerializer<Object>(Object.class);

        // 设置值(value)的序列化采用FastJsonRedisSerializer。
        redisTemplate.setValueSerializer(kryoRedisSerializer);
        redisTemplate.setHashValueSerializer(kryoRedisSerializer);
        // 设置键(key)的序列化采用StringRedisSerializer。
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        redisTemplate.setHashKeySerializer(new StringRedisSerializer());

        redisTemplate.afterPropertiesSet();
        return redisTemplate;
    }
}

2.利用1注册的RedisTemplate客户端构造多级缓存管理器,并交给Spring容器管理

package org.github.roger.cache.config;

import org.github.roger.MultiLayeringCacheManager;
import org.github.roger.manager.ICacheManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.data.redis.core.RedisTemplate;

@Configuration
@Import({RedisConfig.class})
public class ICacheManagerConfig {


    @Bean
    public ICacheManager cacheManager(RedisTemplate<String, Object> redisTemplate) {
        MultiLayeringCacheManager layeringCacheManager = new MultiLayeringCacheManager(redisTemplate);

        return layeringCacheManager;
    }
}

3.创建多级缓存测试类

        3.1) 测试 org.github.roger.manager.ICacheManager#getCache(java.lang.String, org.github.roger.settings.MultiLayeringCacheSetting)

          该方法的功能: 根据缓存名称获取缓存API操作接口,获取到直接返回,如果获取不到,就创建一个,使用

org.github.roger.manager.AbstractCacheManager#getMissingCache方法指定一级缓存和二级缓存分别是什么。

 

package org.github.roger.cache.core;

import org.github.roger.cache.ICache;
import org.github.roger.cache.config.ICacheManagerConfig;
import org.github.roger.enumeration.ExpireMode;
import org.github.roger.manager.ICacheManager;
import org.github.roger.settings.FirstCacheSetting;
import org.github.roger.settings.MultiLayeringCacheSetting;
import org.github.roger.settings.SecondaryCacheSetting;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import java.util.Collection;
import java.util.concurrent.TimeUnit;

// SpringJUnit4ClassRunner再Junit环境下提供Spring TestContext Framework的功能。
@RunWith(SpringJUnit4ClassRunner.class)
// @ContextConfiguration用来加载配置ApplicationContext,其中classes用来加载配置类
@ContextConfiguration(classes = {ICacheManagerConfig.class})
public class CacheCoreTest {
    private Logger logger = LoggerFactory.getLogger(CacheCoreTest.class);

    @Autowired
    private ICacheManager cacheManager;

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    private MultiLayeringCacheSetting layeringCacheSetting1;
    private MultiLayeringCacheSetting layeringCacheSetting2;
    private MultiLayeringCacheSetting layeringCacheSetting4;
    private MultiLayeringCacheSetting layeringCacheSetting5;

    @Before
    public void before() {
        // 测试 CacheManager getCache方法
        FirstCacheSetting firstCacheSetting1 = new FirstCacheSetting(10, 1000, 4, TimeUnit.SECONDS, ExpireMode.WRITE);
        SecondaryCacheSetting secondaryCacheSetting1 = new SecondaryCacheSetting(10, 4, TimeUnit.SECONDS, true, true, true,1);
        layeringCacheSetting1 = new MultiLayeringCacheSetting(firstCacheSetting1, secondaryCacheSetting1);

        // 二级缓存可以缓存null,时间倍率是1
        FirstCacheSetting firstCacheSetting2 = new FirstCacheSetting(10, 1000, 5, TimeUnit.SECONDS, ExpireMode.WRITE);
        SecondaryCacheSetting secondaryCacheSetting2 = new SecondaryCacheSetting(3000, 14, TimeUnit.SECONDS, true, true,true, 1);
        layeringCacheSetting2 = new MultiLayeringCacheSetting(firstCacheSetting2, secondaryCacheSetting2);

        // 二级缓存可以缓存null,时间倍率是10
        FirstCacheSetting firstCacheSetting4 = new FirstCacheSetting(10, 1000, 5, TimeUnit.SECONDS, ExpireMode.WRITE);
        SecondaryCacheSetting secondaryCacheSetting4 = new SecondaryCacheSetting(100, 70, TimeUnit.SECONDS, true, true, true,10);
        layeringCacheSetting4 = new MultiLayeringCacheSetting(firstCacheSetting4, secondaryCacheSetting4);


        // 二级缓存不可以缓存null
        FirstCacheSetting firstCacheSetting5 = new FirstCacheSetting(10, 1000, 5, TimeUnit.SECONDS, ExpireMode.WRITE);
        SecondaryCacheSetting secondaryCacheSetting5 = new SecondaryCacheSetting(10, 7, TimeUnit.SECONDS, true, false,true, 1);
        layeringCacheSetting5 = new MultiLayeringCacheSetting(firstCacheSetting5, secondaryCacheSetting5);

    }

    @Test
    public void testGetCache(){
        String cacheName = "cache:name";
        ICache cache1 = cacheManager.getCache(cacheName, layeringCacheSetting1);
        ICache cache2 = cacheManager.getCache(cacheName, layeringCacheSetting1);
        Assert.assertEquals(cache1, cache2);

        ICache cache3 = cacheManager.getCache(cacheName, layeringCacheSetting2);
        Collection<ICache> caches = cacheManager.getCache(cacheName);
        Assert.assertTrue(caches.size() == 2);
        Assert.assertNotEquals(cache1, cache3);
    }
}

   3.2)测试缓存的过期时间

package org.github.roger.cache.core;

import lombok.extern.slf4j.Slf4j;
import org.github.roger.MultiLayeringCache;
import org.github.roger.cache.ICache;
import org.github.roger.cache.config.ICacheManagerConfig;
import org.github.roger.cache.redis.RedisCache;
import org.github.roger.enumeration.ExpireMode;
import org.github.roger.manager.ICacheManager;
import org.github.roger.settings.FirstCacheSetting;
import org.github.roger.settings.MultiLayeringCacheSetting;
import org.github.roger.settings.SecondaryCacheSetting;
import org.github.roger.utils.RedisCacheKey;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import java.util.Collection;
import java.util.concurrent.TimeUnit;

// SpringJUnit4ClassRunner再Junit环境下提供Spring TestContext Framework的功能。
@RunWith(SpringJUnit4ClassRunner.class)
// @ContextConfiguration用来加载配置ApplicationContext,其中classes用来加载配置类
@ContextConfiguration(classes = {ICacheManagerConfig.class})
@Slf4j
public class CacheCoreTest {

    @Autowired
    private ICacheManager cacheManager;

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    private MultiLayeringCacheSetting layeringCacheSetting1;
    private MultiLayeringCacheSetting layeringCacheSetting2;
    private MultiLayeringCacheSetting layeringCacheSetting4;
    private MultiLayeringCacheSetting layeringCacheSetting5;

    @Before
    public void before() {
        // 测试 CacheManager getCache方法
        FirstCacheSetting firstCacheSetting1 = new FirstCacheSetting(10, 1000, 4, TimeUnit.SECONDS, ExpireMode.WRITE);
        SecondaryCacheSetting secondaryCacheSetting1 = new SecondaryCacheSetting(10, 4, TimeUnit.SECONDS, true, true, true, 1);
        layeringCacheSetting1 = new MultiLayeringCacheSetting(firstCacheSetting1, secondaryCacheSetting1);

        // 二级缓存可以缓存null,时间倍率是1
        FirstCacheSetting firstCacheSetting2 = new FirstCacheSetting(10, 1000, 5, TimeUnit.SECONDS, ExpireMode.WRITE);
        SecondaryCacheSetting secondaryCacheSetting2 = new SecondaryCacheSetting(3000, 14, TimeUnit.SECONDS, true, true, true, 1);
        layeringCacheSetting2 = new MultiLayeringCacheSetting(firstCacheSetting2, secondaryCacheSetting2);

        // 二级缓存可以缓存null,时间倍率是10
        FirstCacheSetting firstCacheSetting4 = new FirstCacheSetting(10, 1000, 5, TimeUnit.SECONDS, ExpireMode.WRITE);
        SecondaryCacheSetting secondaryCacheSetting4 = new SecondaryCacheSetting(100, 70, TimeUnit.SECONDS, true, true, true, 10);
        layeringCacheSetting4 = new MultiLayeringCacheSetting(firstCacheSetting4, secondaryCacheSetting4);


        // 二级缓存不可以缓存null
        FirstCacheSetting firstCacheSetting5 = new FirstCacheSetting(10, 1000, 5, TimeUnit.SECONDS, ExpireMode.WRITE);
        SecondaryCacheSetting secondaryCacheSetting5 = new SecondaryCacheSetting(10, 7, TimeUnit.SECONDS, true, false, true, 1);
        layeringCacheSetting5 = new MultiLayeringCacheSetting(firstCacheSetting5, secondaryCacheSetting5);

    }

    @Test
    public void testGetCache() {
        String cacheName = "cache:name";
        ICache cache1 = cacheManager.getCache(cacheName, layeringCacheSetting1);
        ICache cache2 = cacheManager.getCache(cacheName, layeringCacheSetting1);
        Assert.assertEquals(cache1, cache2);

        ICache cache3 = cacheManager.getCache(cacheName, layeringCacheSetting2);
        Collection<ICache> caches = cacheManager.getCache(cacheName);
        Assert.assertTrue(caches.size() == 2);
        Assert.assertNotEquals(cache1, cache3);
    }

    @Test
    public void testCacheExpiration() {
        //一级缓存的有效时间是在写入之后,4秒
        String cacheName = "cache:name";
        String cacheKey1 = "cache:key1";
        MultiLayeringCache cache1 = (MultiLayeringCache) cacheManager.getCache(cacheName, layeringCacheSetting1);
        cache1.get(cacheKey1, () -> initCache(String.class));
        // 测试一级缓存值及过期时间
        String str1 = cache1.getFirstCache().get(cacheKey1, String.class);
        String st2 = cache1.getFirstCache().get(cacheKey1, () -> initCache(String.class));
        log.debug("========================:{}", str1);
        Assert.assertTrue(str1.equals(st2));
        Assert.assertTrue(str1.equals(initCache(String.class)));
        sleep(5);
        Assert.assertNull(cache1.getFirstCache().get(cacheKey1, String.class));
        // 看日志是不是走了二级缓存
        cache1.get(cacheKey1, () -> initCache(String.class));
        log.debug("***********************");
        log.debug("***********************");
        log.debug("***********************");
        //二级缓存的有效时间是10秒,在失效前 4秒强制刷新缓存
        str1 = cache1.getSecondCache().get(cacheKey1, String.class);
        st2 = cache1.getSecondCache().get(cacheKey1, () -> initCache(String.class));
        Assert.assertTrue(st2.equals(str1));
        Assert.assertTrue(str1.equals(initCache(String.class)));
        sleep(5);
        // 看日志是不是走了自动刷新
        RedisCacheKey redisCacheKey = ((RedisCache) cache1.getSecondCache()).getRedisCacheKey(cacheKey1);
        cache1.get(cacheKey1, () -> initCache(String.class));
        sleep(6);
        Long ttl = redisTemplate.getExpire(redisCacheKey.getKey());
        log.debug("========================ttl 1:{}", ttl);
        Assert.assertNotNull(cache1.getSecondCache().get(cacheKey1));
        sleep(5);
        ttl = redisTemplate.getExpire(redisCacheKey.getKey());
        log.debug("========================ttl 2:{}", ttl);
        Assert.assertNull(cache1.getSecondCache().get(cacheKey1));
    }

    private <T> T initCache(Class<T> t) {
        log.debug("加载缓存");
        return (T) "test";
    }

    private void sleep(int time) {
        try {
            Thread.sleep(time * 1000);
        } catch (InterruptedException e) {
            log.error(e.getMessage(), e);
        }
    }
}

    3.测试删除某个缓存key

	13:54:50.799 [main] INFO org.github.roger.cache.redis.RedisCache 
		- 清除redis缓存 key= cache:name:cache:key2 
	13:55:16.762 [main] DEBUG org.github.roger.listener.RedisPublisher 
		- redis消息发布者向频道【cache:name】发布了【RedisPubSubMessage(cacheName=cache:name, key=cache:key2, messageType=EVICT)】消息

	13:57:06.707 [RedisMessageListenerContainer-3] DEBUG org.github.roger.listener.RedisMessageListener 
		- redis消息订阅者接收到频道【cache:name】发布的消息。消息内容:{"cacheName":"cache:name","key":"cache:key2","messageType":"EVICT"}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值