美文网首页
手动实现springboot的@Cacheableh注解

手动实现springboot的@Cacheableh注解

作者: 赵恩栋 | 来源:发表于2022-04-10 21:18 被阅读0次

思考:

java中执行某个service方法,先判断缓存中有没有该方法的返回值。

如果有的话,直接在redis缓存中取得数据并返回给controller。

如果没有的话,先执行改service,得到的结果放到redis中.第二次将直接在redis中取得数据

在springboot中就有@cacheable相关注解实现类似的业务。在这里我们使用自定义注解的方式实现该业务流程

Springboot整合redis

步骤一:在pom.xml中导入相关依赖

<dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.75</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
        </dependency>
    </dependencies>

步骤二:写配置文件

server:
  port: 8000

spring:
  redis:
    database: 2
    host: 127.0.0.1
    port: 6379
    #连接超时时间(ms)
    timeout: 5000
    jedis:
      pool:
        # 连接池最大连接数(使用负值表示没有限制)
        max-active: -1
        # 连接池最大阻塞等待时间(使用负值表示没有限制)
        max-wait: -1

步骤三:业务中使用RedisTemplate<Object,Object> redisTemplate实现redis的操作

package com.shida.service.impl;

import com.shida.annotation.RedisAfterFind;
import com.shida.service.HelloService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

/**
 * Description:
 *
 * @author mfei
 * Date: 2022/3/22 14:47
 **/
@Service
public class HelloServiceImpl implements HelloService {

    @Autowired
    private RedisTemplate<Object,Object> redisTemplate;

    private String key = "getHello";

    @Override
    @RedisAfterFind(key = "hello")
    public Object getHello() {

        System.out.println("-----进入了此方法-----");
        String user = "15+张三";

        redisTemplate.opsForValue().set(key,user);
        System.out.println("-------结束方法-----");
        return user;
    }

    @Override
    @RedisAfterFind(key = "hello1")
    public Object getHello1() {
        System.out.println("-----进入了此方法-----");
        String user = "16+张三";

        redisTemplate.opsForValue().set(key,user);
        System.out.println("-------结束方法-----");
        return user;
    }

    @Override
    @RedisAfterFind(key = "hello2")
    public Object getHello2() {
        System.out.println("-----进入了此方法-----");
        String user = "18+张三";

        redisTemplate.opsForValue().set(key,user);
        System.out.println("-------结束方法-----");
        return user;
    }


    @Override
    public String getRedis() {
        String age = "年龄为" + redisTemplate.opsForValue().get("age");
        return age;
    }
}

发现问题:

redis存储格式为/dfafd/b63/fdfd疑似乱码(其实是编码的问题)

解决方案:重写RedisTemplate

package com.shida.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;

/**
 * Description:
 *
 * @author mfei
 * Date: 2022/3/22 16:01
 **/
@Configuration
public class RedisConfig {


    @Bean
    public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
        RedisTemplate<Object, Object> template = new RedisTemplate();
        StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
        GenericJackson2JsonRedisSerializer genericJackson2JsonRedisSerializer = new GenericJackson2JsonRedisSerializer();

        template.setConnectionFactory(redisConnectionFactory);
        template.setKeySerializer(stringRedisSerializer);
        template.setHashKeySerializer(stringRedisSerializer);
        template.setValueSerializer(genericJackson2JsonRedisSerializer);
        template.setHashValueSerializer(genericJackson2JsonRedisSerializer);
        return template;
    }

}

使用注解+AOP方法实现redi方法缓存

package com.shida.common;

import java.lang.annotation.*;

/**
 * @author mfei
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface RedisAopFind {

    String key();
    int seconds() default -1;

}
package com.shida.common;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.DefaultParameterNameDiscoverer;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.Expression;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;

/**
 * Description:
 *
 * @author mfei
 * Date: 2022/3/19 16:45
 **/
@Aspect
@Component
public class RedisAop {

    @Autowired
    private RedisTemplate<Object,Object> redisTemplate;


    @Before(value = "@annotation(com.shida.common.RedisAopFind)")
    public void doBefore(){
        System.out.println("---------方法执行前---------");
    }

    @Around("@annotation(com.shida.common.RedisAopFind)")
    public Object around(ProceedingJoinPoint point) throws Throwable {
        Object result = null;

        MethodSignature signature = (MethodSignature) point.getSignature();
        RedisAopFind redisAopFind = signature.getMethod().getAnnotation(RedisAopFind.class);
        String key = redisAopFind.key();


        Method method = signature.getMethod();
        // -------- 使用spel表达式,可忽视------
        //创建解析器
        SpelExpressionParser parser = new SpelExpressionParser();
        //获取表达式
        Expression expression = parser.parseExpression(key);
        //设置解析上下文(有哪些占位符,以及每种占位符的值)
        EvaluationContext context = new StandardEvaluationContext();
        //获取参数值
        Object[] args = point.getArgs();

        //获取运行时参数的名称
        DefaultParameterNameDiscoverer discoverer = new DefaultParameterNameDiscoverer();
        String[] parameterNames = discoverer.getParameterNames(method);
        for (int i = 0; i < parameterNames.length; i++) {
            context.setVariable(parameterNames[i],args[i].toString());
        }
        //解析,获取替换后的结果
        String result1 = expression.getValue(context).toString();
        System.out.println(result1);
        // ---------------------------------------
        
        
        Boolean aBoolean = redisTemplate.hasKey(result1);
        if (aBoolean) {
            return redisTemplate.opsForValue().get(result1);
        }
        result = point.proceed();
        redisTemplate.opsForValue().set(result1,result);
        return result;
    }


}

相关文章

网友评论

      本文标题:手动实现springboot的@Cacheableh注解

      本文链接:https://www.haomeiwen.com/subject/aokbsrtx.html