Redis緩存系列--(五)自定義Redis緩存注解的使用


自定義Redis緩存注解的實現

我們在Spring的框架中,可以使用注解的形式(@EnableCache和@Cacheable)來實現對查詢的數據進行Redis的緩存,我們自己其實也可以自定義一個緩存注解來實現redis緩存的功能。

編寫自定義緩存注解

首先,我們要自定義一個Redis緩存注解,之后要將該注解標注到對應的方法上去,代碼如下:

/**
 * 對方法啟用Redis緩存,使其具有方法前判斷緩存,方法后如果沒有緩存則存儲Redis緩存
 * 緩存key的格式為:value::key,具體的數值由用戶傳遞的注解參數來提供
 * @author young
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyRedisCacheable {
    /**
     * Redis緩存key的前綴
     * @return
     */
    String value() default "";

    /**
     * Redis緩存key的后綴
     * @return
     */
    String key() default "";
}

編寫具體AOP代理方法類

注解只是用來標注當前的方法要用來做什么,同時傳遞相應操作所需要的參數信息。具體要在標注的方法前后實現什么功能,還需要通過Spring AOP的面向切面編程來實現對方法前后所需要進行的處理。具體代碼如下:

/**
 * MyRedisCacheable注解的具體處理類,實現對標注方法執行前做Redis緩存檢查處理,方法執行后執行緩存Redis數據的處理
 * @author young
 */
@Component
@Aspect
public class CacheAspect {
    private Logger logger =  LoggerFactory.getLogger(CacheAspect.class);

    @Autowired
    private RedisTemplate redisTemplate;

    /**
     * 設置注解的切入點,即指定切入的方法為
     */
    @Pointcut("@annotation(com.young.redis.aop.MyRedisCacheable)")
    public void cachePointcut(){

    }

    /**
     * 定義需要進行AOP切面編程的切點是哪個,也即標注MyRedisCacheable注釋的方法
     * @param proceedingJoinPoint 當前切入方法的上下文
     * @return
     */
    @Around("cachePointcut()")
    public Object doRedisCache(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        Object value = null;
        try {
            //獲取切入方法的標簽
            MethodSignature signature = (MethodSignature) proceedingJoinPoint.getSignature();
            //通過該標簽來獲取修飾的方法和方法參數
            Method method = proceedingJoinPoint.getTarget().getClass().
                    getMethod(signature.getName(),signature.getMethod().getParameterTypes());
            //獲取當前方法的注解以及注解的參數
            MyRedisCacheable myRedisCacheable = method.getAnnotation(MyRedisCacheable.class);
            //redis key的EL表達式
            String keyEL = myRedisCacheable.key();
            //redis key的前綴
            String prifix = myRedisCacheable.value();

            //解析EL表達式
            ExpressionParser expressionParser = new SpelExpressionParser();
            Expression expression =expressionParser.parseExpression(keyEL);

            //用來組合EL表達式和方法參數的EL上下文對象
            EvaluationContext evaluationContext = new StandardEvaluationContext();

            //獲取方法的參數,將參數放入evaluationContext
            Object[] args = proceedingJoinPoint.getArgs();
            DefaultParameterNameDiscoverer defaultParameterNameDiscoverer = new DefaultParameterNameDiscoverer();
            String[] parameterNames = defaultParameterNameDiscoverer.getParameterNames(method);
            for (int i = 0; i < parameterNames.length; i++) {
                evaluationContext.setVariable(parameterNames[i],args[i].toString());
            }

            //使用Expression和EvaluationContext來解析EL表達式
            String cacheKey = prifix + "::" + expression.getValue(evaluationContext).toString();

            //判斷緩存是否存在
            value = redisTemplate.opsForValue().get(cacheKey);
            if(value != null){
                logger.info("從緩存中讀取到的key:" + cacheKey +",value:" + value);
                return value;
            }

            //不存在則執行數據庫方法進行查詢
            value = proceedingJoinPoint.proceed();

            //將查詢到的內容存到Redis
            redisTemplate.opsForValue().set(cacheKey,value);
        }catch (Throwable throwable){
            throwable.printStackTrace();
        }
        //方法執行后返回查詢結果
        return value;
    }
}

編寫配置類

無論是在SpringMvc框架還是Springboot框架中,都可以通過編寫配置類的方式來配置需要加載的bean對象,具體的配置類代碼如下:

/**
 * 通過注解的形式來配置spring中的bean
 * 使用自定義注解方式來實現Redis緩存
 * @author young
 */
@Configuration
@EnableAspectJAutoProxy //開啟AOP自動代理
public class AppConfig {

    /**
     * 通過注釋來獲取properties配置文件中的自定義值,引號里邊為EL表達式
     */
    @Value("${spring.redis.host}")
    String host;

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

    /**
     * 通過RedisConnectionFactory來獲取RedisTemplate,從而進行Redis的相關操作(注解方式同樣需要)
     * @return
     */
    @Bean
    public RedisConnectionFactory redisConnectionFactory(){
        //配置Redis的主機和端口
        RedisStandaloneConfiguration redisStandaloneConfiguration = new RedisStandaloneConfiguration();
        redisStandaloneConfiguration.setHostName(host);
        redisStandaloneConfiguration.setPort(port);

        //
        RedisConnectionFactory redisConnectionFactory = new JedisConnectionFactory(redisStandaloneConfiguration);
        return redisConnectionFactory;
    }

    /**
     * 加載RedisTemplate bean
     * @param redisConnectionFactory
     * @return
     */
    @Bean
    public RedisTemplate redisTemplate(RedisConnectionFactory redisConnectionFactory){
        RedisTemplate redisTemplate = new RedisTemplate();
        redisTemplate.setConnectionFactory(redisConnectionFactory);
        //指定Redis序列化的方式
        redisTemplate.setKeySerializer(StringRedisSerializer.UTF_8);
        return redisTemplate;
    }
}

這樣,一個自定義Redis緩存注解的實現也就基本完成了,這對於我們了解注解的底層原理也是很有幫助的。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM