前言:在一次开发过程中,需求是 先查询redis缓存,没有再查db,完成一次操作,当时只顾着开发业务,没有时间整理组件的使用,现在空闲下来, 利用 AOP切面来进行 组件的开发,来进行个人经验总结, AOP思想作用不仅仅是我刚阐述的场景. 这里不阐述AOP的思想,只巩固它的用法.
下面以自身业务代码,进行自我总结梳理.
- 添加xml配置
- <!-- 配置注解驱动 --> <mvc:annotation-driven/>
-
<!--扫描 --><context:component-scan base-package="com.xxx"/>
- AOP的 配置 ,这里我使用的 注解标签来实现
- 自定义注解类
/** * @Date 2019/10/10 15:42 * @Created by Z.xh * 用于redis操作 表情用于添加注解 */ @Target({ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) public @interface RedisCacheAnno { /** * key的前缀 * * @return */ String value(); /** * key的规则,可以使用springEL表达式,可以使用方法执行的一些参数 */ String key(); }
-
aop切面书写
/** * @Date 2019/10/10 15:45 * @Created by Z.xh * 用于使用redis 利用aop 存入缓存的操作, 解除代码耦合性 */ @Component public class RedisCacheAspect { @Autowired private RedisTemplate redisTemplate; // 定义相应的事件 @Around("cachePointcut()") public Object doCache(ProceedingJoinPoint joinPoint) { Object object = null; try { // 0-1、 当前方法上注解的内容 MethodSignature signature = (MethodSignature) joinPoint.getSignature(); Method method = joinPoint.getTarget().getClass().getMethod(signature.getName(), signature.getMethod().getParameterTypes()); RedisCacheAnno cacheAnnotation = method.getAnnotation(RedisCacheAnno.class); String keyEl = cacheAnnotation.key(); String prefix = cacheAnnotation.value(); // 0-2、 前提条件:拿到作为key的依据 - 解析springEL表达式 // 创建解析器 ExpressionParser parser = new SpelExpressionParser(); Expression expression = parser.parseExpression(keyEl); EvaluationContext context = new StandardEvaluationContext(); // 参数 // 添加参数 Object[] args = joinPoint.getArgs(); DefaultParameterNameDiscoverer discover = new DefaultParameterNameDiscoverer(); String[] parameterNames = discover.getParameterNames(method); for (int i = 0; i < parameterNames.length; i++) { context.setVariable(parameterNames[i], args[i].toString()); } // 解析 String key = prefix + "::" + expression.getValue(context).toString(); object = redisTemplate.opsForValue().get(key); if (null != object) { System.out.println("从缓存中获取"); // 从缓存中获取 return object; } // 从数据库中获取 object = joinPoint.proceed(); System.out.println("从数据库中获取"); // 存入redis 中 redisTemplate.opsForValue().set(key, object); } catch (Throwable throwable) { throwable.printStackTrace(); } return object; } }
在需要的使用 aop的方法上 贴上相应的注解标签即可,
----------------------------------------------------------------
因为aop 配置也分为2中 一种xml配置, 一种是注解配置,这里只是xml的一种实现方式, 我配置的也是 环绕切面, 在aop本身来说,依然有很多中切面的方式,在这个过程中, 切面表达式也有很多种,需要根据自身的业务需求来配置切面表达式, 最常用的是
execution 表达,需要了解这些的,可以自行百度每一个的作用.