Springboot之自定义注解实现Redis缓冲更新获取删除

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/yhflyl/article/details/87716969

Redis获取策略

检测缓冲是否失效,未失效获取缓冲,获取超时,捕获异常,查数据表,重置缓冲,并设置失效时间,返回数据。

Redis跟更新策略

获取key缓冲时间是否已经失效,没有失效设置为失效。
当用户再次获取数据是,会自动更新缓冲,并设置缓冲失效时间。

使用方式

    // 自定义RedisCacheable注解,设置value和key,并设置有效时间为3600*100
    @Override
    @RedisCacheable(Value = "job", Key = "page", time = 3600*100)
    public List<PartTimeJob> jobAll(Integer page, Integer limit) {
        RowBounds rowBounds = new RowBounds((page - 1) * 8, limit);
        return jobMapper.selectPage(rowBounds, new EntityWrapper<PartTimeJob>().where("job_check", 1).orderBy("job_time_pulish", false));
    }

	// 自定义RedisCacheUpdate注解
    @Override
    @RedisCacheUpdate(Value = "job", Key = "page")
    public Integer updatePartJob(Integer id, Integer status) {
        return jobMapper.changeCheckStatus(id, status);
    }

原理:

通过AOP+反射,通过切面环绕对方法进行缓冲操作。

Redis配置类

使用lettuce作为redis连接池,lettuce是springboot2默认的客户端,自动集成,如果要使用jedis配置麻烦,并且lettuce是线程安全可以自动扩展的;jedis是非线程安全。

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Bean;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;

/**
 * lettuce的redis连接池
 * @author 进击的Coder
 * @date 2019/1/31
 */
@Configuration
@AutoConfigureAfter(RedisAutoConfiguration.class)
public class RedisConfig {


    @Bean
    public RedisTemplate<String, Object> redisTemplate (LettuceConnectionFactory connectionFactory) {
        RedisTemplate<String, Object> template = new RedisTemplate<String, Object>();
        template.setConnectionFactory(connectionFactory);
        Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
        ObjectMapper om = new ObjectMapper();
        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        jackson2JsonRedisSerializer.setObjectMapper(om);
        StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
        // key采用String的序列化方式
        template.setKeySerializer(stringRedisSerializer);
        // hash的key也采用String的序列化方式
        template.setHashKeySerializer(stringRedisSerializer);
        // value序列化方式采用jackson
        template.setValueSerializer(jackson2JsonRedisSerializer);
        // hash的value序列化方式采用jackson
        template.setHashValueSerializer(jackson2JsonRedisSerializer);
        template.afterPropertiesSet();
        // 开启事务
        template.setEnableTransactionSupport(true);
        return template;
    }

}

自定义的注解

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

/**
 * @author 易水●墨龙吟
 * @Description 自定义的查询缓冲注解
 * @create 2019-02-16 15:02
 */
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface RedisCacheable {

    String Value() default "";

    String Key() default "";

    long time() default 0L;

}

AOP方法类

import com.lehui.molong.config.redis.annotation.RedisCacheable;
import com.lehui.molong.config.redis.utils.RedisUtil;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import java.text.SimpleDateFormat;
import java.util.Date;


/**
 * @author 易水●墨龙吟
 * @Description
 * @create 2019-02-16 15:39
 * Order 拦截器执行顺序
 */
@Aspect
@Order(1)
@Component
public class InterceptorSelect extends Common {

    @Autowired
    private RedisUtil redisUtil;

    @Pointcut("@annotation(redisCacheable)")
    public void pointCut(RedisCacheable redisCacheable) {}

	// 设置切面为加有 @RedisCacheable注解的方法
    @Around("@annotation(redisCacheable)")
    public Object around(ProceedingJoinPoint proceedingJoinPoint, RedisCacheable redisCacheable) throws Throwable {
        System.out.println("拦截到方法:" + proceedingJoinPoint.getSignature().getName() + "方法...");
        return redisSelect(proceedingJoinPoint, redisCacheable);
    }


    @AfterThrowing(pointcut = "@annotation(redisCacheable)", throwing = "error")
    public void afterThrowing (Throwable  error, RedisCacheable redisCacheable){
        System.out.println("出现异常");
    }


    /**
     * 获取缓冲
     * @param proceedingJoinPoint
     * @param redisCacheable
     * @return
     */
    private Object redisSelect (ProceedingJoinPoint proceedingJoinPoint, RedisCacheable redisCacheable) throws Throwable {
        String value = redisCacheable.Value();
        String key = redisCacheable.Key();
        // 通过反射获取方法的参数、value、key 拼接为一个 value:key [...参数]的key值
        String newKey = super.getKey(proceedingJoinPoint, value, key);
        Object result = null;
        try {
            if(redisUtil.hasKey(newKey)) {
                long expire = redisUtil.getExpire(newKey);
                if (expire > System.currentTimeMillis()) {
                    result = redisUtil.get(newKey);
                } else {
                    result = getNewRedis(proceedingJoinPoint, redisCacheable, newKey, result);
                }
            } else {
                result = getNewRedis(proceedingJoinPoint, redisCacheable, newKey, result);
            }
        } catch (Exception exception) {
            System.out.println("Redis连接超时");
            result = getNewRedis(proceedingJoinPoint, redisCacheable, newKey, result);
        }
        return result;
    }


    /**
     * 获取数据库数据,并更新缓冲
     * @param proceedingJoinPoint
     * @param redisCacheable
     * @param newKey
     * @param result
     * @return
     * @throws Throwable
     */
    private Object getNewRedis (ProceedingJoinPoint proceedingJoinPoint, RedisCacheable redisCacheable, String newKey, Object result) throws Throwable {
        Long time = redisCacheable.time();
        System.out.println(time);
        long newTime = System.currentTimeMillis() + time;
        System.out.println(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date(newTime)));
        result = proceedingJoinPoint.proceed();
        if(time > 0L) {
            redisUtil.set(newKey, result, newTime);
        } else {
            redisUtil.set(newKey, result);
        }
        return result;
    }
}

效果图

初次请求

在这里插入图片描述

再次请求

在这里插入图片描述

其他

完整结构
在这里插入图片描述
工具类和其他的注解类太多代码,就不一一展示了;有需要的就可以评论发出邮箱,我给大家发一份。

猜你喜欢

转载自blog.csdn.net/yhflyl/article/details/87716969