• SpringBoot之集成Spring AOP


    SpringBoot集成ApringAOP步骤如下:

    1.导包

                    <dependency>
    			<groupId>org.springframework.boot</groupId>
    			<artifactId>spring-boot-starter-aop</artifactId>
    		</dependency>
    
    
    		<!-- https://mvnrepository.com/artifact/com.google.guava/guava -->
                    <!-- com.google.common.collect.Maps 依赖-->
    		<dependency>
    			<groupId>com.google.guava</groupId>
    			<artifactId>guava</artifactId>
    			<version>24.1-jre</version>
    		</dependency>
    
    		<dependency>
    			<groupId>com.alibaba</groupId>
    			<artifactId>fastjson</artifactId>
    			<version>1.2.43</version>
    		</dependency>        
    

     2.这里主要介绍通知的类型有:前置通知、后置返回通知、后置最终通知、后置异常通知、环绕通知;详细如下:

       --------------------  准备工作  ---------------------

        a . 创建Aspect切面类;    

     package com.zdj.springboot_aop;
    
    /**
     * Created by Administrator on 2018/3/28.
     */
    
    /**
     * 1.先创建一个Aspect切面类
     */
    @Component
    @Aspect
    public class WebControllerAop {
    
    }
    

          b. 指定切点 

    /**
     * 2. 指定切点
     * 匹配com.zdj.springboot_aop.Controller包及其子包下面的所有类的所有方法
     */
        @Pointcut("execution(* com.zdj.springboot_aop.Controller..*.*(..))")
        public  void executeService(){
    
        }

               c. 创建Controller类 处理请求

    package com.zdj.springboot_aop.Controller;
    
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    /**
     * Created by Administrator on 2018/3/28.
     */
    
    @RestController
    @RequestMapping("/aop")
    public class AopTestController {
    
    }

      2.1 前置通知

                  2.1.1  配置前置通知

     1    /*
     2      *  01 . 前置通知:方法调用前被调用
     3      */
     4     @Before("executeService()")
     5     public void doBeforeAdvice(JoinPoint joinPoint){//  通过JoinPoint 获取通知的签名信息,如目标方法名,目标方法参数信息等
     6         System.out.println("我是前置通知");
     7         Object[] obj=joinPoint.getArgs();//获取目标方法的参数信息
     8         joinPoint.getThis(); // AOP代理类信息
     9         joinPoint.getTarget(); // 代理的目标对象
    10         Signature signature=joinPoint.getSignature(); //  用的最多,通知的签名
    11         System.out.println("代理的方法是 : "+signature.getName()); //  打印 代理的是哪一个方法
    12         // AOP 代理的名字
    13         System.out.println("AOP 代理的名字 : "+signature.getDeclaringTypeName());
    14         signature.getDeclaringType();//  AOP代理类的类(class)信息
    15 
    16         /*
    17           通过RequestContextHolder获取请求信息,如session 信息 ;
    18          */
    19         //  获取RequestAttributes
    20         RequestAttributes requestAttributes= RequestContextHolder.getRequestAttributes();
    21         //  从requestAttributes中获取HttpServletRequest信息
    22         HttpServletRequest request=(HttpServletRequest)requestAttributes.resolveReference(RequestAttributes.REFERENCE_REQUEST);
    23         //  获取session信息
    24         HttpSession session=(HttpSession)requestAttributes.resolveReference(RequestAttributes.REFERENCE_SESSION);
    25 
    26         System.out.println("请求 : "+request+" ,  HttpSession : "+session);
    27         Enumeration<String> enumerations=request.getParameterNames();
    28 //        Map<String,String> parameterMaps=new HashMap<>();
    29         Map<String,String> parameterMaps= Maps.newHashMap();
    30         while(enumerations.hasMoreElements()){
    31             String parameter=enumerations.nextElement();
    32             parameterMaps.put(parameter,request.getParameter(parameter));
    33         }
    34 
    35 //        String str=JSON.toJSONString(parameterMaps);
    36         String str= JSON.toJSONString(parameterMaps);//   alibaba.fastjson
    37         if(obj.length>0){
    38             System.out.println("请求参数信息为 : "+ str );
    39         }
    40 
    41     }

    注:  

    关于调用 JoinPoint 和 RequestContextHolder。
    通过JoinPoint可以获得通知的签名信息,如目标方法名、目标方法参数信息等。
    通过RequestContextHolder来获取请求信息,Session信息。

        2.2.2  在Controller类里添加一个请求处理方法来测试一下前置通知:

     1     @RequestMapping("/testBeforeService.do")
     2     public String testBeforeService(String key ,String value){
     3         return "key : "+key+ ", value : "+value;
     4         /*
     5         url:  http://localhost:8080/aop/testBeforeService.do?key=zdj&value=123
     6         执行结果 : 
           我是前置通知
    7 代理的方法是 : testBeforeService 8 AOP 代理的名字 : com.zdj.springboot_aop.Controller.AopTestController 9 请求 : org.apache.catalina.connector.RequestFacade@4f8cf74e , HttpSession : org.apache.catalina.session.StandardSessionFacade@7b37a638 10 请求参数信息为 : {"value":"123","key":"zdj"} 11 */ 12 }

      2.2  后置返回通知

        2.2.1   配置后置返回通知的代码如下:

     1      /**
     2      * 02  .后置返回通知
     3      * 需要注意:
     4      *      如果第一个参数是JoinPoint,则第二个参数是返回值的信息
     5      *      如果参数中的第一个不是JoinPoint,则第一个参数是returning中对应的参数,
     6      *    returning 限定了只有目标方法返回值与通知方法相应参数类型时才能
     7      * 执行后置返回通知,否则不执行;
     8      * 对于returning对应的通知方法参数为Object类型将匹配任何目标返回值
     9      * @param joinPoint
    10      * @param keys
    11      */
    12     @AfterReturning(value="execution(* com.zdj.springboot_aop.Controller..*.*(..))",returning = "keys")
    13     public void doAfterReturningAdvice1(JoinPoint joinPoint,Object keys){
    14         System.out.println("后置通知执行了!!");
    15         System.out.println("第一个后置返回通知的返回值是 :"+keys);
    16     }
    17 
    18     @AfterReturning(value="execution(* com.zdj.springboot_aop.Controller..*.*(..))",returning = "keys",argNames="keys")
    19     public void doAfterReturningAdvice2(String keys){ // 通知方法形影参数的类型是String
    20         System.out.println("第二个后置返回通知的返回值是 :"+keys);
    21     }

        2.2.2  测试后置返回通知

     1 @RequestMapping("/testAfterReturning1.do")
     2     public String testAfterReturning1(String key){
     3         return "key = "+key;
     4         /*
     5             url :  http://localhost:8080/aop/testAfterReturning1.do?key=zdj&value=123
     6             后置通知执行了!!
     7             第一个后置返回通知的返回值是 :key = zdj
     8             第二个后置返回通知的返回值是 :key = zdj
     9          */
    10     }
    11 
    12     @RequestMapping("/testAfterReturning2.do")
    13     public Integer testAfterReturning2(Integer key){
    14         return key;
    15         /*
    16             url :  http://localhost:8080/aop/testAfterReturning2.do?key=111222&value=123
    17 
    18             后置通知执行了!!
    19             第一个后置返回通知的返回值是 :111222
    20 
    21             注 : 因第二个后置通知首参不是JoinPoint,并且相应参数类型是String,而该目标方法的返回值类型是Integer,所以第二个后置通知方法不执行
    22 
    23          */
    24     }

      2.3  后置异常通知

        2.3.1  配置后置异常通知如下:

     1      /**
     2      *  03 . 后置异常通知
     3      *       定义一个名字,该名字用于匹配通知实现方法的一个参数名,当目标方法抛出异常返回后,将把目标方法抛出的异常传给通知方法;
     4      *  throwing 限定了只有目标方法抛出的异常与通知方法相应参数异常类型时才能执行后置异常通知,否则不执行,
     5      *      对于throwing对应的通知方法参数为Throwable类型将匹配任何异常。
     6      */
     7     @AfterThrowing(value="executeService()",throwing = "exception")
     8     public void doAfterThrowingAdvice(JoinPoint joinPoint,Throwable exception){
     9         // 目标方法名
    10         System.out.println(joinPoint.getSignature().getName());
    11         if(exception instanceof NullPointerException){
    12             System.out.println("发生了空指针异常");
    13         }
    14     }

        2.3.2  controller测试后置异常通知如下:

     1     @RequestMapping("/testAfterThrowing.do")
     2     public  String testAfterThrowing(String key){
     3         throw new NullPointerException();
     4         /*
     5         url : http://localhost:8080/aop/testAfterThrowing.do?key=zdk&value=123
     6         我是前置通知
     7         代理的方法是 : testAfterThrowing
     8         AOP 代理的名字 : com.zdj.springboot_aop.Controller.AopTestController
     9         请求 : org.apache.catalina.connector.RequestFacade@41b8dcce ,  HttpSession : org.apache.catalina.session.StandardSessionFacade@33c33c37
    10         请求参数信息为 : {"value":"123","key":"zdk"}
    11         testAfterThrowing
    12         发生了空指针异常
    13         */
    14     }

      2.4  后置最终通知

        2.4.1  配置后置最终通知如下:

    1      /**
    2      * 04 . 后置最终通知(目标方法只要执行完了就会执行后置通知方法)
    3      */
    4 
    5     @After("executeService()")
    6     public void doAfterService(JoinPoint joinPoint){
    7         System.out.println("后置最终通知执行了!");
    8     }

        2.4.2  controller测试后置最终通知:

     1     @RequestMapping("/testAfter1.do")
     2     public String testAfter1(String key){
     3         throw new NullPointerException();
     4         /*
     5         url: http://localhost:8080/aop/testAfter1.do?key=zdj&value=123
     6         后置最终通知执行了!
     7          */
     8     }
     9 
    10     @RequestMapping("/testAfter2.do")
    11     public String testAfter2(String key){
    12         return key;
    13         /*
    14         url: http://localhost:8080/aop/testAfter2.do?key=zdj&value=123
    15         后置最终通知执行了!
    16          */
    17     }

      2.5  环绕通知

        2.5.1 配置环绕通知如下:

     1      /**
     2      * 环绕通知:
     3      *   环绕通知非常强大,可以决定目标方法是否执行,什么时候执行,执行时是否需要替换方法参数,执行完毕是否需要替换返回值。
     4      *   环绕通知第一个参数必须是org.aspectj.lang.ProceedingJoinPoint类型
     5      */
     6     @Around("execution(* com.zdj.springboot_aop.Controller..*.testAround*(..))")
     7     public Object doAroundService(ProceedingJoinPoint proceedingJoinPoint){
     8         System.out.println("环绕通知的目标方法名为 : "+proceedingJoinPoint.getSignature().getName());
     9         try {
    10             Object object=proceedingJoinPoint.proceed();
    11             return object;
    12         } catch (Throwable throwable) {
    13             throwable.printStackTrace();
    14         }
    15         return  null;
    16     }

        2.5.2  controller 测试环绕通知如下:

     1     @RequestMapping("/testAroundService.do")
     2     public String testAroundService(String key){
     3         return "环绕通知 : " + key;
     4         /*
     5         url : http://localhost:8080/aop/testAroundService.do?key=1122
     6         环绕通知的目标方法名为 : testAroundService
     7 
     8         当访问 http://localhost:8080/aop/testAfter2.do?key=1122&value=sjshhjdh,不符合环绕通知的切入规则,所以环绕通知不会执行;
     9          */
    10     }

    3.  完整代码如下:

      1 package com.zdj.springboot_aop;
      2 
      3 import com.alibaba.fastjson.JSON;
      4 import com.google.common.collect.Maps; // guava   24.1-jar
      5 import org.aspectj.lang.JoinPoint;
      6 import org.aspectj.lang.ProceedingJoinPoint;
      7 import org.aspectj.lang.Signature;
      8 import org.aspectj.lang.annotation.*;
      9 import org.springframework.stereotype.Component;
     10 import org.springframework.web.context.request.RequestAttributes;
     11 import org.springframework.web.context.request.RequestContextHolder;
     12 
     13 //import com.google.common.collect.Maps;
     14 import javax.servlet.http.HttpServletRequest;
     15 import javax.servlet.http.HttpSession;
     16 import java.util.Enumeration;
     17 import java.util.HashMap;
     18 import java.util.Map;
     19 
     20 /**
     21  * Created by Administrator on 2018/3/28.
     22  */
     23 
     24 /**
     25  * 1.先创建一个Aspect切面类
     26  */
     27 @Component
     28 @Aspect
     29 public class WebControllerAop {
     30 
     31 /**
     32  * 2. 指定切点
     33  * 匹配com.zdj.springboot_aop.Controller包及其子包下面的所有类的所有方法
     34  */
     35     @Pointcut("execution(* com.zdj.springboot_aop.Controller..*.*(..))")
     36     public  void executeService(){
     37 
     38     }
     39 
     40     /**
     41      *  01 . 前置通知:方法调用前被调用
     42      */
     43     @Before("executeService()")
     44     public void doBeforeAdvice(JoinPoint joinPoint){//  通过JoinPoint 获取通知的签名信息,如目标方法名,目标方法参数信息等
     45         System.out.println("我是前置通知");
     46         Object[] obj=joinPoint.getArgs();//获取目标方法的参数信息
     47         joinPoint.getThis(); // AOP代理类信息
     48         joinPoint.getTarget(); // 代理的目标对象
     49         Signature signature=joinPoint.getSignature(); //  用的最多,通知的签名
     50         System.out.println("代理的方法是 : "+signature.getName()); //  打印 代理的是哪一个方法
     51         // AOP 代理的名字
     52         System.out.println("AOP 代理的名字 : "+signature.getDeclaringTypeName());
     53         signature.getDeclaringType();//  AOP代理类的类(class)信息
     54 
     55         /*
     56           通过RequestContextHolder获取请求信息,如session 信息 ;
     57          */
     58         //  获取RequestAttributes
     59         RequestAttributes requestAttributes= RequestContextHolder.getRequestAttributes();
     60         //  从requestAttributes中获取HttpServletRequest信息
     61         HttpServletRequest request=(HttpServletRequest)requestAttributes.resolveReference(RequestAttributes.REFERENCE_REQUEST);
     62         //  获取session信息
     63         HttpSession session=(HttpSession)requestAttributes.resolveReference(RequestAttributes.REFERENCE_SESSION);
     64 
     65         System.out.println("请求 : "+request+" ,  HttpSession : "+session);
     66         Enumeration<String> enumerations=request.getParameterNames();
     67 //        Map<String,String> parameterMaps=new HashMap<>();
     68         Map<String,String> parameterMaps= Maps.newHashMap();
     69         while(enumerations.hasMoreElements()){
     70             String parameter=enumerations.nextElement();
     71             parameterMaps.put(parameter,request.getParameter(parameter));
     72         }
     73 
     74 //        String str=JSON.toJSONString(parameterMaps);
     75         String str= JSON.toJSONString(parameterMaps);//   alibaba.fastjson
     76         if(obj.length>0){
     77             System.out.println("请求参数信息为 : "+ str );
     78         }
     79 
     80     }
     81 
     82     /**
     83      * 02  .后置返回通知
     84      * 需要注意:
     85      *      如果第一个参数是JoinPoint,则第二个参数是返回值的信息
     86      *      如果参数中的第一个不是JoinPoint,则第一个参数是returning中对应的参数,
     87      *    returning 限定了只有目标方法返回值与通知方法相应参数类型时才能
     88      * 执行后置返回通知,否则不执行;
     89      * 对于returning对应的通知方法参数为Object类型将匹配任何目标返回值
     90      * @param joinPoint
     91      * @param keys
     92      */
     93     @AfterReturning(value="execution(* com.zdj.springboot_aop.Controller..*.*(..))",returning = "keys")
     94     public void doAfterReturningAdvice1(JoinPoint joinPoint,Object keys){
     95         System.out.println("后置通知执行了!!");
     96         System.out.println("第一个后置返回通知的返回值是 :"+keys);
     97     }
     98 
     99     @AfterReturning(value="execution(* com.zdj.springboot_aop.Controller..*.*(..))",returning = "keys",argNames="keys")
    100     public void doAfterReturningAdvice2(String keys){ // 通知方法形影参数的类型是String
    101         System.out.println("第二个后置返回通知的返回值是 :"+keys);
    102     }
    103 
    104     /**
    105      *  03 . 后置异常通知
    106      *       定义一个名字,该名字用于匹配通知实现方法的一个参数名,当目标方法抛出异常返回后,将把目标方法抛出的异常传给通知方法;
    107      *  throwing 限定了只有目标方法抛出的异常与通知方法相应参数异常类型时才能执行后置异常通知,否则不执行,
    108      *      对于throwing对应的通知方法参数为Throwable类型将匹配任何异常。
    109      */
    110     @AfterThrowing(value="executeService()",throwing = "exception")
    111     public void doAfterThrowingAdvice(JoinPoint joinPoint,Throwable exception){
    112         // 目标方法名
    113         System.out.println(joinPoint.getSignature().getName());
    114         if(exception instanceof NullPointerException){
    115             System.out.println("发生了空指针异常");
    116         }
    117     }
    118 
    119 
    120     /**
    121      * 04 . 后置最终通知(目标方法只要执行完了就会执行后置通知方法)
    122      */
    123 
    124     @After("executeService()")
    125     public void doAfterService(JoinPoint joinPoint){
    126         System.out.println("后置最终通知执行了!");
    127     }
    128 
    129     /**
    130      * 环绕通知:
    131      *   环绕通知非常强大,可以决定目标方法是否执行,什么时候执行,执行时是否需要替换方法参数,执行完毕是否需要替换返回值。
    132      *   环绕通知第一个参数必须是org.aspectj.lang.ProceedingJoinPoint类型
    133      */
    134     @Around("execution(* com.zdj.springboot_aop.Controller..*.testAround*(..))")
    135     public Object doAroundService(ProceedingJoinPoint proceedingJoinPoint){
    136         System.out.println("环绕通知的目标方法名为 : "+proceedingJoinPoint.getSignature().getName());
    137         try {
    138             Object object=proceedingJoinPoint.proceed();
    139             return object;
    140         } catch (Throwable throwable) {
    141             throwable.printStackTrace();
    142         }
    143         return  null;
    144     }
    145 }
    View Code
     1 package com.zdj.springboot_aop.Controller;
     2 
     3 import org.springframework.web.bind.annotation.RequestMapping;
     4 import org.springframework.web.bind.annotation.RestController;
     5 
     6 /**
     7  * Created by Administrator on 2018/3/28.
     8  */
     9 
    10 @RestController
    11 @RequestMapping("/aop")
    12 public class AopTestController {
    13 
    14     @RequestMapping("/testBeforeService.do")
    15     public String testBeforeService(String key ,String value){
    16         return "key : "+key+ ", value : "+value;
    17         /*
    18         url:  http://localhost:8080/aop/testBeforeService.do?key=zdj&value=123
    19         我是前置通知
    20         代理的方法是 : testBeforeService
    21         AOP 代理的名字 : com.zdj.springboot_aop.Controller.AopTestController
    22         请求 : org.apache.catalina.connector.RequestFacade@4f8cf74e ,  HttpSession : org.apache.catalina.session.StandardSessionFacade@7b37a638
    23         请求参数信息为 : {"value":"123","key":"zdj"}
    24          */
    25     }
    26 
    27     @RequestMapping("/testAfterReturning1.do")
    28     public String testAfterReturning1(String key){
    29         return "key = "+key;
    30         /*
    31             url :  http://localhost:8080/aop/testAfterReturning1.do?key=zdj&value=123
    32             后置通知执行了!!
    33             第一个后置返回通知的返回值是 :key = zdj
    34             第二个后置返回通知的返回值是 :key = zdj
    35          */
    36     }
    37 
    38     @RequestMapping("/testAfterReturning2.do")
    39     public Integer testAfterReturning2(Integer key){
    40         return key;
    41         /*
    42             url :  http://localhost:8080/aop/testAfterReturning2.do?key=111222&value=123
    43 
    44             后置通知执行了!!
    45             第一个后置返回通知的返回值是 :111222
    46 
    47             注 : 因第二个后置通知首参不是JoinPoint,并且相应参数类型是String,而该目标方法的返回值类型是Integer,所以第二个后置通知方法不执行
    48          */
    49     }
    50 
    51     @RequestMapping("/testAfterThrowing.do")
    52     public  String testAfterThrowing(String key){
    53         throw new NullPointerException();
    54         /*
    55         url : http://localhost:8080/aop/testAfterThrowing.do?key=zdk&value=123
    56         我是前置通知
    57         代理的方法是 : testAfterThrowing
    58         AOP 代理的名字 : com.zdj.springboot_aop.Controller.AopTestController
    59         请求 : org.apache.catalina.connector.RequestFacade@41b8dcce ,  HttpSession : org.apache.catalina.session.StandardSessionFacade@33c33c37
    60         请求参数信息为 : {"value":"123","key":"zdk"}
    61         testAfterThrowing
    62         发生了空指针异常
    63         */
    64     }
    65 
    66     @RequestMapping("/testAfter1.do")
    67     public String testAfter1(String key){
    68         throw new NullPointerException();
    69         /*
    70         url: http://localhost:8080/aop/testAfter1.do?key=zdj&value=123
    71         后置最终通知执行了!
    72          */
    73     }
    74 
    75     @RequestMapping("/testAfter2.do")
    76     public String testAfter2(String key){
    77         return key;
    78         /*
    79         url: http://localhost:8080/aop/testAfter2.do?key=zdj&value=123
    80         后置最终通知执行了!
    81          */
    82     }
    83 
    84     @RequestMapping("/testAroundService.do")
    85     public String testAroundService(String key){
    86         return "环绕通知 : " + key;
    87         /*
    88         url : http://localhost:8080/aop/testAroundService.do?key=1122
    89         环绕通知的目标方法名为 : testAroundService
    90 
    91         当访问 http://localhost:8080/aop/testAfter2.do?key=1122&value=sjshhjdh,不符合环绕通知的切入规则,所以环绕通知不会执行;
    92          */
    93     }
    94 
    95 }
    View Code
  • 相关阅读:
    css3边框阴影属性
    web移动端浮层滚动阻止window窗体滚动JS/CSS处理
    css3字体尺寸font-size-adjust属性
    css3文本溢出使用省略标记(…)
    exports 和 module.exports 的区别
    微信小程序——try {} catch (e) {}
    flex布局
    微信小程序——data-*自定义属性
    CSS 隐藏滚动条 但可以滚动
    event.target 和 event.currentTarget 的区别
  • 原文地址:https://www.cnblogs.com/zdj-/p/8665454.html
Copyright © 2020-2023  润新知