需求是这样的,业务代码须要使用到缓存功能以减小数据库压力,使用redis来实现,而且须要生成缓存的key由方法的传参拼接而成(貌似也只能这样才能保证一样的select查询能够使用缓存),简单的方式就是在须要缓存的方法内加上大概这样的逻辑:查询缓存--->没有则查询数据库 --->查询结果以key-value形式放入缓存,这样对业务代码形成了侵入,而且产生大量重复的代码,很不优雅,因此决定本身封装一个缓存模块,在须要缓存的地方只须要加入一个注解便可。java
首先自定义一个注解redis
package com.example.test.aspect; import java.lang.annotation.*; @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) @Inherited public @interface MyCache { String value() default ""; }
定义切面spring
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项目express
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",结果以下springboot