1. 程式人生 > >SpringBoot+SpringAop通知使用例項

SpringBoot+SpringAop通知使用例項

package com.zdj.springboot_aop;

import com.alibaba.fastjson.JSON;
import com.google.common.collect.Maps; // guava   24.1-jar
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component
; import org.springframework.web.context.request.RequestAttributes; import org.springframework.web.context.request.RequestContextHolder; //import com.google.common.collect.Maps; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpSession; import java.util.Enumeration; import java.util.HashMap; import
java.util.Map; /** * Created by Administrator on 2018/3/28. */ /** * 1.先建立一個Aspect切面類 */ @Component @Aspect public class WebControllerAop { /** * 2. 指定切點 * 匹配com.zdj.springboot_aop.Controller包及其子包下面的所有類的所有方法 */ @Pointcut("execution(* com.zdj.springboot_aop.Controller..*.*(..))") public void
executeService(){ } /** * 01 . 前置通知:方法呼叫前被呼叫 */ @Before("executeService()") public void doBeforeAdvice(JoinPoint joinPoint){// 通過JoinPoint 獲取通知的簽名信息,如目標方法名,目標方法引數資訊等 System.out.println("我是前置通知"); Object[] obj=joinPoint.getArgs();//獲取目標方法的引數資訊 joinPoint.getThis(); // AOP代理類資訊 joinPoint.getTarget(); // 代理的目標物件 Signature signature=joinPoint.getSignature(); // 用的最多,通知的簽名 System.out.println("代理的方法是 : "+signature.getName()); // 列印 代理的是哪一個方法 // AOP 代理的名字 System.out.println("AOP 代理的名字 : "+signature.getDeclaringTypeName()); signature.getDeclaringType();// AOP代理類的類(class)資訊 /* 通過RequestContextHolder獲取請求資訊,如session 資訊 ; */ // 獲取RequestAttributes RequestAttributes requestAttributes= RequestContextHolder.getRequestAttributes(); // 從requestAttributes中獲取HttpServletRequest資訊 HttpServletRequest request=(HttpServletRequest)requestAttributes.resolveReference(RequestAttributes.REFERENCE_REQUEST); // 獲取session資訊 HttpSession session=(HttpSession)requestAttributes.resolveReference(RequestAttributes.REFERENCE_SESSION); System.out.println("請求 : "+request+" , HttpSession : "+session); Enumeration<String> enumerations=request.getParameterNames(); // Map<String,String> parameterMaps=new HashMap<>(); Map<String,String> parameterMaps= Maps.newHashMap(); while(enumerations.hasMoreElements()){ String parameter=enumerations.nextElement(); parameterMaps.put(parameter,request.getParameter(parameter)); } // String str=JSON.toJSONString(parameterMaps); String str= JSON.toJSONString(parameterMaps);// alibaba.fastjson if(obj.length>0){ System.out.println("請求引數資訊為 : "+ str ); } } /** * 02 .後置返回通知 * 需要注意: * 如果第一個引數是JoinPoint,則第二個引數是返回值的資訊 * 如果引數中的第一個不是JoinPoint,則第一個引數是returning中對應的引數, * returning 限定了只有目標方法返回值與通知方法相應引數型別時才能 * 執行後置返回通知,否則不執行; * 對於returning對應的通知方法引數為Object型別將匹配任何目標返回值 * @param joinPoint * @param keys */ @AfterReturning(value="execution(* com.zdj.springboot_aop.Controller..*.*(..))",returning = "keys") public void doAfterReturningAdvice1(JoinPoint joinPoint,Object keys){ System.out.println("後置通知執行了!!"); System.out.println("第一個後置返回通知的返回值是 :"+keys); } @AfterReturning(value="execution(* com.zdj.springboot_aop.Controller..*.*(..))",returning = "keys",argNames="keys") public void doAfterReturningAdvice2(String keys){ // 通知方法形影引數的型別是String System.out.println("第二個後置返回通知的返回值是 :"+keys); } /** * 03 . 後置異常通知 * 定義一個名字,該名字用於匹配通知實現方法的一個引數名,當目標方法丟擲異常返回後,將把目標方法丟擲的異常傳給通知方法; * throwing 限定了只有目標方法丟擲的異常與通知方法相應引數異常型別時才能執行後置異常通知,否則不執行, * 對於throwing對應的通知方法引數為Throwable型別將匹配任何異常。 */ @AfterThrowing(value="executeService()",throwing = "exception") public void doAfterThrowingAdvice(JoinPoint joinPoint,Throwable exception){ // 目標方法名 System.out.println(joinPoint.getSignature().getName()); if(exception instanceof NullPointerException){ System.out.println("發生了空指標異常"); } } /** * 04 . 後置最終通知(目標方法只要執行完了就會執行後置通知方法) */ @After("executeService()") public void doAfterService(JoinPoint joinPoint){ System.out.println("後置最終通知執行了!"); } /** * 環繞通知: * 環繞通知非常強大,可以決定目標方法是否執行,什麼時候執行,執行時是否需要替換方法引數,執行完畢是否需要替換返回值。 * 環繞通知第一個引數必須是org.aspectj.lang.ProceedingJoinPoint型別 */ @Around("execution(* com.zdj.springboot_aop.Controller..*.testAround*(..))") public Object doAroundService(ProceedingJoinPoint proceedingJoinPoint){ System.out.println("環繞通知的目標方法名為 : "+proceedingJoinPoint.getSignature().getName()); try { Object object=proceedingJoinPoint.proceed(); return object; } catch (Throwable throwable) { throwable.printStackTrace(); } return null; } }
package com.zdj.springboot_aop.Controller;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * 建立AOP測試Controller.Created by Administrator on 2018/3/28.
 */
@RestController
@RequestMapping("/aop")
public class AopTestController {

    @RequestMapping("/testBeforeService.do")
    public String testBeforeService(String key ,String value){
        return "key : "+key+ ", value : "+value;
        /*
        url:  http://localhost:8080/aop/testBeforeService.do?key=zdj&value=123
        我是前置通知
        代理的方法是 : testBeforeService
        AOP 代理的名字 : com.zdj.springboot_aop.Controller.AopTestController
        請求 : [email protected] ,  HttpSession : [email protected]
        請求引數資訊為 : {"value":"123","key":"zdj"}
         */
}

    @RequestMapping("/testAfterReturning1.do")
    public String testAfterReturning1(String key){
        return "key = "+key;
        /*
            url :  http://localhost:8080/aop/testAfterReturning1.do?key=zdj&value=123
            後置通知執行了!!
            第一個後置返回通知的返回值是 :key = zdj
            第二個後置返回通知的返回值是 :key = zdj
         */
}

    @RequestMapping("/testAfterReturning2.do")
    public Integer testAfterReturning2(Integer key){
        return key;
        /*
            url :  http://localhost:8080/aop/testAfterReturning2.do?key=111222&value=123
            後置通知執行了!!
            第一個後置返回通知的返回值是 :111222
            注 : 因第二個後置通知首參不是JoinPoint,並且相應引數型別是String,而該目標方法的返回值型別是Integer,所以第二個後置通知方法不執行
         */
}

    @RequestMapping("/testAfterThrowing.do")
    public  String testAfterThrowing(String key){
        throw new NullPointerException();
        /*
        url : http://localhost:8080/aop/testAfterThrowing.do?key=zdk&value=123
        我是前置通知
        代理的方法是 : testAfterThrowing
        AOP 代理的名字 : com.zdj.springboot_aop.Controller.AopTestController
        請求 : [email protected] ,  HttpSession : [email protected]
        請求引數資訊為 : {"value":"123","key":"zdk"}
        testAfterThrowing
        發生了空指標異常
        */
}

    @RequestMapping("/testAfter1.do")
    public String testAfter1(String key){
        throw new NullPointerException();
        /*
        url: http://localhost:8080/aop/testAfter1.do?key=zdj&value=123
        後置最終通知執行了!
         */
}

    @RequestMapping("/testAfter2.do")
    public String testAfter2(String key){
        return key;
        /*
        url: http://localhost:8080/aop/testAfter2.do?key=zdj&value=123
        後置最終通知執行了!
         */
}

    @RequestMapping("/testAroundService.do")
    public String testAroundService(String key){
        return "環繞通知 : " + key;
        /*
        url : http://localhost:8080/aop/testAroundService.do?key=1122
        環繞通知的目標方法名為 : testAroundService
        當訪問 http://localhost:8080/aop/testAfter2.do?key=1122&value=sjshhjdh,不符合環繞通知的切入規則,所以環繞通知不會執行;
         */
}

}
package com.zdj.springboot_aop;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

/**
 * Created by Dylan on 2018/6/22.
 */
@SpringBootApplication
public class StartApplication {

    public static void main(String[] args) {
        SpringApplication.run(StartApplication.class, args);
    }


}