"AOP Realizes Redis Cache Business"

AOP realizes caching business

Business needs

  • 1 Use custom annotations to represent business methods, and the return value of the business is stored in the cache

  • 2 Use AOP to intercept annotations and use surround notification methods to achieve business


Prepare in advance

1. Create Redis configuration file (prepare redis node)

创建properties配置文件,里面存入Redis节点

Insert picture description here

#准备redis的节点信息
redis.host=192.168.126.129
redis.port=6379

2. Create a Redis configuration class (the node is handed over to the spring container for management)

创建class类 里面导入配置文件存储的节点信息并且交给spring管理

Insert picture description here

@Configuration //表示一个配置类 一一般会@bean的注解关联
@PropertySource("classpath:/redis.properties") //导入配置文件
public class redis {
    
    

    @Value("${redis.host}")
    private String host;
    @Value("${redis.port}")
    private Integer port;

    @Bean   //将方法的返回值结果,交给spring容器进行管理.
    public Jedis jedis(){
    
    
        return new Jedis(host, port);
    }
}

3. Create a Redis tool class (used to convert objects in JSON format and convert objects to JSON)

把数据库的对象格式转换JSON格式存储缓存中,把缓存的JSON格式转换对象格式传入客户端

Insert picture description here

public class RedisUtl {
    
    

    private static final ObjectMapper MAPPER=new ObjectMapper();
    //对象转json
    public static String toJSON(Object object) {
    
    
        try {
    
    
            return MAPPER.writeValueAsString(object);
        } catch (JsonProcessingException e) {
    
    
            e.printStackTrace();
            throw new RuntimeException();
        }
    }
    //2.JSON转化为对象 要求用户传递什么类型就返回什么对象??
    public static <T> T toObject(String json,Class<T> target){
    
    
        try {
    
    
            return MAPPER.readValue(json, target);
        } catch (JsonProcessingException e) {
    
    
            e.printStackTrace();
            throw new RuntimeException();
        }
    }
}

Initial case

1. Create custom annotations

注解是接口,用来指定目标业务方法,并且拦截

Insert picture description here

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface RedisAopFind {
    
    
    String key();
    int seconds() default -1;
}

Notes used

@Target() ----- This annotation describes the scope of use of the annotation, where is this annotation used

ElementType ----- value

METHOD ----- This annotation is used to describe the method

@Retention() ----- The role is to define how long the annotations annotated by it are retained

RetentionPolicy ----- value

RUNTIME ----- annotations are not only saved in the class file, but still exist after the jvm loads the class file

String key(); ---- define the key value

int seconds() default -1; ---- timeout time default -1 is not timeout by default


2. Annotations indicate business methods

Insert picture description here

  • Here is our custom annotation

  • key is the name of our business method

  • The method described in our custom annotation is intercepted in AOP

3. Initial AOP

3.1 Create a Java class, which means that the created class is a business class of Aop

Insert picture description here

当前的类是处理AOP业务的类

@Component
@Aspect
public class RedisAOP {
    
    

    @Autowired
    private Jedis jedis;

}

@Component ----- This annotation description class is handed over to spring management

@Aspect ----- The class described by this annotation is a class that represents AOP (Aspect Oriented)

   @Autowired
    private Jedis jedis;

我们导入Redis的配置类


4. Business structure


@Component
@Aspect
public class RedisAOP {
    
    

    @Autowired
    private Jedis jedis;
    

    @Around("@annotation(redisAopFind)")
    public Object around(ProceedingJoinPoint joinPointm, RedisAopFind redisAopFind){
    
    
        Object result=null;
        String Key=redisAopFind.key();
        //动态获取方法的参数
        String args= Arrays.toString(joinPointm.getArgs());
        Key = Key + "::" + args;

        if (jedis.exists(Key)){
    
    
            String json=jedis.get(Key);
            //动态获取方法的类型
            MethodSignature methodSignature= (MethodSignature) joinPointm.getSignature();
            Class returnType = methodSignature.getReturnType();

            result = RedisUtl.toObject(json, returnType);
            System.out.println("AOP查询redis缓存");
        }else{
    
    
            try {
    
    
             result =joinPointm.proceed(); //执行下一个通知,执行目标方法

             String json=RedisUtl.toJSON(result);
             if (redisAopFind.seconds()>0){
    
    
                 jedis.setex(Key, redisAopFind.seconds(), json);
             }else {
    
    
                 jedis.set(Key, json);
             }
                System.out.println("AOP查询数据库");
            }catch (Throwable throwable) {
    
    
                throwable.printStackTrace();
            }
        }
        return result;
    }

}

The first step is to intercept the business and encapsulate the KEY

 @Around("@annotation(redisAopFind)")
    public Object around(ProceedingJoinPoint joinPoint, RedisAopFind redisAopFind){
    
    
        Object result=null;
        String Key=redisAopFind.key();
        //动态获取方法的参数
        String args= Arrays.toString(joinPointm.getArgs());
        Key = Key + "::" + args;

First of all, I import our custom annotation @Around is the surround notification, we use the surround notification to intercept the method described by our custom annotation, and get the return value of the method

  • JoinPoint-the entry point method, the object of the target method information being executed, the popular point (we intercept the target method manager)
  • redisAopFind-custom annotations we created
  • redisAopFind.key() – Get the key in the custom annotation, the key value we assign when the annotation describes the target method
  • joinPointm.getArgs() – Get the parameters in the target method, we need string concatenation, so use the tostring method
Key = Key + "::" + args;
  • The obtained key value is spliced ​​with the parameters of the target method to encapsulate the KEY value in redis

prompt:

Our KEY changes and cannot use a fixed key, so if the parameters are spliced, the parameters requested by the client are not the same, and our key values ​​are also dynamically changed, which is easy to distinguish, and the corresponding parameters are also used when storing. Encapsulation

Second step verification

1- The value of KEY exists in Redis (get the value in redis)

if (jedis.exists(Key)){
    
    
    String json=jedis.get(Key);
    //动态获取方法的类型
    MethodSignature methodSignature= (MethodSignature) joinPointm.getSignature();
    Class returnType = methodSignature.getReturnType();

    result = RedisUtl.toObject(json, returnType);
    System.out.println("AOP查询redis缓存");
}
  • Determine whether there is currently our encapsulated KEY in the redis cache

  • If it exists, get to get the value of KEY

String json=jedis.get(Key);
  • joinPointm.getSignature() method to get the signature of the target method

    • We want to assign the method signature of the parent class of joinPointm to use reason.
    • The printed result shows the signature of the target method

Insert picture description here

 MethodSignature methodSignature= (MethodSignature) joinPointm.getSignature();
  • Dynamically obtain the type of the target method based on the signature

  • getReturnType Get the type of the current target method signature (that is, the type of the target method)

  • The printed result shows the type of target method

Insert picture description here

 Class returnType = methodSignature.getReturnType();

缓存中KEY的值转换成目标方法的类型,并返回

result = RedisUtl.toObject(json, returnType);

2- The value of KEY does not exist in redis (query the database and store it in the cache)

else{
    
    
    try {
    
    
     result =joinPointm.proceed(); //执行下一个通知,执行目标方法

     String json=RedisUtl.toJSON(result);
     if (redisAopFind.seconds()>0){
    
    
         jedis.setex(Key, redisAopFind.seconds(), json);
     }else {
    
    
         jedis.set(Key, json);
     }
        System.out.println("AOP查询数据库");
    }catch (Throwable throwable) {
    
    
        throwable.printStackTrace();
    }
}
  • If there is no query data in redis, then directly execute the target method and get it in the database

  • joinPointm.proceed(); execute target method

result =joinPointm.proceed(); 
  • The return value of the target method querying the database is converted to the Json type

String json=RedisUtl.toJSON(result);
  • At present, we have not set the timeout time. If we timeout in the future, the timeout time will be greater than 0. Then define the timeout time we set when storing

  • Store directly if there is no timeout

if (redisAopFind.seconds()>0){
    
    
    jedis.setex(Key, redisAopFind.seconds(), json);
}else {
    
    
    jedis.set(Key, json);
}

Expand

When we define custom annotations, we define the default no timeout, so if we define the timeout time,
Insert picture description here
add the timeout time when the custom annotation describes the method


3. Business completion

return result-returns the result of
Insert picture description here
the client's query The first query is the database, the
second query is the cache

Guess you like

Origin blog.csdn.net/weixin_45103228/article/details/113773727