阅读 234

SpringBoot整合Redis环境并自己实现注解缓存

引入环境

<!--redis-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-redis</artifactId>
    <version>1.4.7.RELEASE</version>
</dependency>
复制代码

配置环境

这里是在Redis单机下多个数据库配置

@Configuration
@EnableCaching
public class RedisConfig extends CachingConfigurerSupport {
    @Value("${redis.database.cache}")
    private int cacheDatabase;
    @Value("${redis.database.cache2}")
    private int cacheDatabase2;
    @Value("${redis.host}")
    private String host;
    @Value("${redis.password}")
    private String password;
    @Value("${redis.port}")
    private int port;
    @Value("${redis.timeout}")
    private int timeout;
    @Value("${redis.pool.max-idle}")
    private int maxIdle;
    @Value("${redis.pool.min-idle}")
    private int minIdle;
    @Value("${redis.pool.max-wait}")
    private long maxWait;

    private Duration timeToLive = Duration.ZERO;
    public void setTimeToLive(Duration timeToLive){
        this.timeToLive = timeToLive;
    }

    @Autowired
    private RedisConnectionFactory redisConnectionFactory;

    @Bean
    public CacheManager cacheManager(RedisConnectionFactory redisConnectionFactory){
        RedisCacheConfiguration redisCacheConfiguration = RedisCacheConfiguration.defaultCacheConfig().entryTtl(Duration.ofHours(1));
        return RedisCacheManager.builder(RedisCacheWriter.nonLockingRedisCacheWriter(redisConnectionFactory)).cacheDefaults(redisCacheConfiguration).build();
    }

    @Bean
    public JedisPoolConfig getJedisPoolConfig(){
        JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
        jedisPoolConfig.setBlockWhenExhausted(true);
        jedisPoolConfig.setTestOnBorrow(true);
        jedisPoolConfig.setMaxIdle(maxIdle);
        jedisPoolConfig.setMinIdle(minIdle);
        jedisPoolConfig.setMaxWaitMillis(10000);
        return jedisPoolConfig;
    }

    @Bean(name = "cacheRedisTemplate")
    public RedisTemplate<String, Object> getCacheRedisTemplate(){
        System.out.println(host);
        System.out.println(port);
        JedisConnectionFactory jedisConnectionFactory = new JedisConnectionFactory();
        jedisConnectionFactory.setPoolConfig(getJedisPoolConfig());
        jedisConnectionFactory.setDatabase(cacheDatabase);
        jedisConnectionFactory.setHostName(host);
        jedisConnectionFactory.setPassword(password);
        jedisConnectionFactory.setPort(port);
        jedisConnectionFactory.setTimeout(timeout);
        jedisConnectionFactory.afterPropertiesSet();
        RedisTemplate<String, Object> template = new RedisTemplate<>();
        template.setConnectionFactory(jedisConnectionFactory);
        Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
        template.setKeySerializer(jackson2JsonRedisSerializer);
        template.setHashKeySerializer(jackson2JsonRedisSerializer);
        template.setHashValueSerializer(jackson2JsonRedisSerializer);
        ObjectMapper om = new ObjectMapper();
        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        jackson2JsonRedisSerializer.setObjectMapper(om);
        template.setValueSerializer(jackson2JsonRedisSerializer);
        template.afterPropertiesSet();
        return template;
    }

    @Bean(name = "cacheRedisTemplate2")
    public RedisTemplate<String, Object> getCacheRedisTemplate2(){
        System.out.println(host);
        System.out.println(port);
        JedisConnectionFactory jedisConnectionFactory = new JedisConnectionFactory();
        jedisConnectionFactory.setPoolConfig(getJedisPoolConfig());
        jedisConnectionFactory.setDatabase(cacheDatabase2);
        jedisConnectionFactory.setHostName(host);
        jedisConnectionFactory.setPassword(password);
        jedisConnectionFactory.setPort(port);
        jedisConnectionFactory.setTimeout(timeout);
        jedisConnectionFactory.afterPropertiesSet();
        RedisTemplate<String, Object> template = new RedisTemplate<>();
        template.setConnectionFactory(jedisConnectionFactory);
        Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
        template.setKeySerializer(jackson2JsonRedisSerializer);
        template.setHashKeySerializer(jackson2JsonRedisSerializer);
        template.setHashValueSerializer(jackson2JsonRedisSerializer);
        ObjectMapper om = new ObjectMapper();
        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        jackson2JsonRedisSerializer.setObjectMapper(om);
        template.setValueSerializer(jackson2JsonRedisSerializer);
        template.afterPropertiesSet();
        return template;
    }
}
复制代码

参数就自己在配置文件中填写就可以了。

利用AOP机制,进行注解缓存

定义接口

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface RedisCache {
    String cacheNames() default "";

    String key() default "";

    String cacheSource() default "null";
}
复制代码

这里定义了缓存名,缓存key值和数据库源

实现环绕切面逻辑

@Aspect
@Component
public class RedisCacheable {
    @Resource
    @Qualifier("cacheRedisTemplate")
    private RedisTemplate<String, Object> cacheRedisTemplate;

    @Resource
    @Qualifier("cacheRedisTemplate2")
    private RedisTemplate<String, Object> cacheRedisTemplate2;

    private Map<String, RedisTemplate<String, Object>> cacheMap = null;

    @PostConstruct
    private void initCache(){
        cacheMap = new HashMap<>();
        cacheMap.put("cacheRedisTemplate", cacheRedisTemplate);
        cacheMap.put("cacheRedisTemplate2", cacheRedisTemplate2);
    }

    @Pointcut("@annotation(redisCache)")
    public void pointCut(RedisCache redisCache){}

    @Around("pointCut(redisCache)")
    public Object around(ProceedingJoinPoint pjp, RedisCache redisCache) throws Throwable {
        Object result = null;
        String methodName = pjp.getSignature().getName();
        try {
            if (cacheMap.get(redisCache.cacheSource()).hasKey(redisCache.key())){
                result = cacheMap.get(redisCache.cacheSource()).opsForValue().get(redisCache.key());
            }else {
                result = pjp.proceed();
                ValueOperations<String, Object> operations = cacheMap.get(redisCache.cacheSource()).opsForValue();
                operations.set(redisCache.key(), result);
                cacheMap.get(redisCache.cacheSource()).opsForValue().set(redisCache.key(), result);
            }
        } catch (Throwable e) {
            //异常通知
            System.out.println("The method " + methodName + " occurs exception:" + e);
            throw new RuntimeException(e);
        }
        //后置通知
        System.out.println("The method " + methodName + " ends");
        return result;
    }
}

复制代码

这里就是对两个Redis模板进行管理,根据cacheSource来动态切换数据源,提高可扩展性。

同理可以扩写清除缓存、更新缓存和实现其他淘汰策略等。

测试

service层

public interface CacheService {
    String test(String id, String content);
    String test2(String id, String content);
}
复制代码
@Service
@CacheConfig(cacheManager = "")
public class CacheServiceImpl implements CacheService {

    @Override
    @RedisCache(cacheNames = "test", key = "11", cacheSource = "cacheRedisTemplate")
    public String test(String id, String content) {
        return content;
    }

    @Override
    @RedisCache(cacheNames = "test", key = "11", cacheSource = "cacheRedisTemplate2")
    public String test2(String id, String content) {
        return content;
    }
}
复制代码

controller层

@RestController
@RequestMapping("/trace")
public class TraceController {
    @Autowired
    private CacheService cacheService;

    @GetMapping("/1")
    public String test(@RequestParam("id") String id, @RequestParam("content") String content){
        return cacheService.test(id, content);
    }

    @GetMapping("/2")
    public String test2(@RequestParam("id") String id, @RequestParam("content") String content){
        return cacheService.test2(id, content);
    }
}
复制代码

用浏览器测试

确认Redis是空的

1.jpg
浏览器输入的接口是用Redis数据库0,key值11,内容是test_1

2.jpg
查看数据库,已经有了

3.jpg 浏览器输入的接口是用Redis数据库0,key值不变,内容是test_1_update,但是因为有缓存,所有还是出现了test_1

4.jpg

浏览器输入的接口是用Redis数据库1,key值11,内容是test_2

5.jpg

查看数据库,已经有了

6.jpg
浏览器输入的接口是用Redis数据库1,key值不变,内容是test_2_update,但是因为有缓存,所有还是出现了test_2

7.jpg

能力有限,有错误之处请指正!!!

文章分类
后端