SpringBoot集成ApringAOP步驟以下:java
1.導包web
<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.這裏主要介紹通知的類型有:前置通知、後置返回通知、後置最終通知、後置異常通知、環繞通知;詳細以下:spring
-------------------- 準備工做 ---------------------apache
a . 建立Aspect切面類; json
package com.zdj.springboot_aop; /** * Created by Administrator on 2018/3/28. */ /** * 1.先建立一個Aspect切面類 */ @Component @Aspect public class WebControllerAop { }
b. 指定切點 springboot
/** * 2. 指定切點 * 匹配com.zdj.springboot_aop.Controller包及其子包下面的全部類的全部方法 */ @Pointcut("execution(* com.zdj.springboot_aop.Controller..*.*(..))") public void executeService(){ }
c. 建立Controller類 處理請求session
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 前置通知app
2.1.1 配置前置通知ide
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 }
注: spring-boot
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 }
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 }