首页 > 编程语言 > 详细

Spring Aop的学习(复习)

时间:2020-08-01 22:11:09      阅读:138      评论:0      收藏:0      [点我收藏+]

Spring Aop的学习(复习)

之前看视频学了spring aop,然后没咋用忘得差不多了,最近用到过索性就抓起来复习一遍

遇到的名词

  1. 切面(Aspect): 切面是通知和切点的结合 | 一个关注点的模块化,这个关注点可能会横切多个对象

  2. 连接点(Joinpoint): 在程序执行过程中某个特定的点

  3. 通知(Advice): AOP 框架中的增强处理。通知描述了切面何时执行以及如何执行增强处理。

    1. Before 前置通知

    2. AfterReturning 后置通知 在连接点正常执行完成后执行,如果连接点抛出异常,则不会执行。

    3. Around 环绕通知

    4. AfterThrowing 异常通知 在连接点抛出异常后执行。

    5. After 最终通知 在连接点执行完成后执行,不管是正常执行完成,还是抛出异常,都会执行返回通知中的内容。

    6. 顺序 前置通知→环绕通知→正常返回通知/异常返回通知→返回通知

  4. 切入点(Pointcut): 指定哪些方法需要拦截

  5. 织入(Weaving): 把切面连接到其它的应用程序类型或者对象上,并创建一个被通知的对象。

  6. 方法签名(Signature): 用于获取方法信息(需要转成(MethodSignature)),方法的名字,所处类的全限定名

  7. 方法信息(Method): 就Method类的实例

  8. 方法参数: 就方法的参数值,按顺序的

  9. 目标对象: 就是那个连接点或者说加强的方法位于的对象,相当于获取了this or this._this = this;

  10. SpEL: spring提供的表达式,比el??

使用

  1. 引入依赖spring-boot-starter-aop

  2. 如果遇到使用shiro导致方法二次增强导致注解丢失而404,可添加如下代码在shiro的配置类里

    @Bean
    public static DefaultAdvisorAutoProxyCreator getDefaultAdvisorAutoProxyCreator() {
        DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
        defaultAdvisorAutoProxyCreator.setUsePrefix(true);
        return defaultAdvisorAutoProxyCreator;
    }
    
  3. 编写Aop类,加上@Aspect@Component注解

  4. 然后写个方法,通过注解里的值选择切点,注解的类型就是通知(Advice)方法

  5. 使用样例

    1. Aop类关键代码

      /**
       * AfterReturning 后置通知方法 注解的参数是切点表达式
       *
       * @param joinPoint            切入点
       * @param userNotifyAnnotation 方法上的注解,用于获取注解里的值
       * @param returnVal            方法的返回值,不能修改,只能看
       */
      @AfterReturning(value = "@annotation(userNotifyAnnotation)", returning = "returnVal")
      public void after(JoinPoint joinPoint, UserNotifyAnno userNotifyAnnotation, Object returnVal) {
          System.out.println("----------------------");
          Signature signature = joinPoint.getSignature();// 方法签名
          Method method = ((MethodSignature) signature).getMethod(); //方法信息
          Object[] in = joinPoint.getArgs();// 方法参数
          Object target = joinPoint.getTarget();// 目标对象 相当于 this
          System.out.println("签名:" + signature);
          System.out.println("返回值:" + returnVal);
          System.out.println("方法名字:" + method.getName());
          System.out.println("第一个参数:" + in[0]);
          System.out.println("解析SpEL的值:" + parseSpEL(userNotifyAnnotation.type(), method, in, String.class)); // 方法见附录
          System.out.println("======================");
      }
      
    2. 自定义注解

      import java.lang.annotation.*;
      
      @Target(ElementType.METHOD) //方法
      @Retention(RetentionPolicy.RUNTIME) //运行时
      @Documented
      public @interface UserNotifyAnno {
          String value() default "";
          String type() default "";
      
      }
      
    3. 控制器部分代码

      @UserNotifyAnno(value = "test1", type = "#num")
      @GetMapping("/test1")
      public Result Test1(HttpServletRequest request, @RequestParam("str") String str,
                          @RequestParam(value = "num", defaultValue = "2") Integer num) {
          System.out.println(str);
          return Result.succ("jojo");
      }
      
    4. 运行结果

      ======================
      签名:Result com.yuan.controller.TestController.Test1(HttpServletRequest,String,Integer)
      返回值:Result(code=200, msg=jojo, data=null)
      方法名字:Test1
      第一个参数:org.apache.catalina.connector.RequestFacade@2543f995
      解析SpEL的值:6
      ======================
      

附录

解析SpEL表达式

    /**
     * 解析SpEL表达式
     *
     * @param key    SpEL表达式
     * @param method 反射得到的方法
     * @param args   反射得到的方法参数
     * @return 解析后SpEL表达式对应的值
     */
    private String parseKey(String key, Method method, Object[] args) {
        // 获取被拦截方法参数名列表(使用Spring支持类库)
        LocalVariableTableParameterNameDiscoverer u = new LocalVariableTableParameterNameDiscoverer();
        String[] paraNameArr = u.getParameterNames(method);
        // 使用SpEL进行key的解析
        ExpressionParser parser = new SpelExpressionParser();
        // SpEL上下文
        StandardEvaluationContext context = new StandardEvaluationContext();
        // 把方法参数放入SpEL上下文中
        for (int i = 0; i < paraNameArr.length; i++) {
            // 使用setVariable方法来注册自定义变量
            context.setVariable(paraNameArr[i], args[i]);
        }
        return parser.parseExpression(key).getValue(context, String.class);
    }

技术分享图片

Spring AOP只对方法调用连接点进行捕获,最多只能获取到方法的签名信息

参考

SpringBoot切面Aop的demo简单讲解

[Spring AOP——Spring 中面向切面编程](https://www.cnblogs.com/joy99/p/10941543.html)

Spring Aop的学习(复习)

原文:https://www.cnblogs.com/somegenki/p/13416191.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!