使用spring EL表达式+自定义切面封装缓存模块

  需求是这样的,业务代码需要使用到缓存功能以减少数据库压力,使用redis来实现,并且需要生成缓存的key由方法的传参拼接而成(貌似也只能这样才能保证同样的select查询可以使用缓存),简单的方式就是在需要缓存的方法内加上大概这样的逻辑:查询缓存--->没有则查询数据库 --->查询结果以key-value形式放入缓存,这样对业务代码造成了侵入,并且产生大量重复的代码,很不优雅,所以决定自己封装一个缓存模块,在需要缓存的地方只需要加入一个注解即可。

  首先自定义一个注解

package com.example.test.aspect;


import java.lang.annotation.*;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@Inherited
public @interface MyCache {

    String value() default "";
}

  定义切面

package com.example.test.aspect;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;


@Component
@Aspect
public class MyAspect {

    //切入点,带有Myche注解并且是UserService类下的方法
    @Pointcut("@annotation(com.example.test.aspect.MyCache)&&execution(* com.example.test.service.UserService.*(..))")
    public  void pointCut(){};

    @Around("pointCut()")
    public Object cache(ProceedingJoinPoint joinPoint)throws Throwable{
        //获取方法签名
        MethodSignature  methodSignature = (MethodSignature) joinPoint.getSignature();
        //获取目标方法
        Method method = methodSignature.getMethod();
//       Method method2 = joinPoint.getTarget().getClass().getMethod(methodSignature.getName(),methodSignature.getParameterTypes());
        //获取方法上的注解
        MyCache myCache = method.getDeclaredAnnotation(MyCache.class);
        //得到el表达式
        String el = myCache.value();
        //解析el表达式,将#id等替换为参数值
        ExpressionParser expressionParser = new SpelExpressionParser();
        Expression expression = expressionParser.parseExpression(el);
        EvaluationContext context = new StandardEvaluationContext();
        String[] parameterNames = methodSignature.getParameterNames();
        Object[] args = joinPoint.getArgs();
        for (int i = 0; i <parameterNames.length ; i++) {
            context.setVariable(parameterNames[i],args[i]);
        }
        String key = expression.getValue(context).toString();
        System.out.println(key);
        //根据key从缓存中拿数据,这里省略
        
        //如果缓存中没有则执行目标方法
        Object o =   joinPoint.proceed();
        //将结果放入缓存,这里省略
        
        return o;
        
    }
}

  测试的service

package com.example.test.service;

import com.example.test.aspect.MyCache;
import org.springframework.stereotype.Service;

@Service
public class UserService implements UserServiceInterface{
    

    @MyCache("'asd_' + #id")
    @Override
    public void addUser(String id,String name){
        System.out.println(id + "----" + name);
    }
}

  测试类,这里是springboot项目

package com.example.test;

import com.example.test.service.UserService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

@RunWith(SpringRunner.class)
@SpringBootTest
public class TestApplicationTests {

    @Autowired
    private UserService userService;

    @Test
    public void contextLoads() {
        System.out.println(userService.getClass().getName());

        userService.addUser("12345" ,"zhagnsan");
    }

}

  执行结果如下:

  修改UserService上的注解为:"'asd_' + #id + '_' + #name",结果如下

猜你喜欢

转载自www.cnblogs.com/hhhshct/p/10636159.html