1. 程式人生 > >Spring AOP、Spring AOP 實現原理

Spring AOP、Spring AOP 實現原理

一、為什麼會出現AOP
一個場景

把大象裝進冰箱分三步:
(1)、開啟冰箱
(2)、把大象裝進冰箱
(3)、關上冰箱
把老虎裝進冰箱分三步:
(1)、開啟冰箱
(2)、把老虎裝進冰箱
(3)、關上冰箱
如果把1000種動物裝進冰箱,還需要計時怎麼辦?顯然不能1000個類中都加程式碼

交叉業務邏輯,系統級的服務 類比 開啟冰箱門,關閉冰箱門
主業務邏輯 類比 把動物放進冰箱,主業務執行前後新增系統級服務,比如要加事務,列印日誌

優化:
1.將xxx放到冰箱中這個過程封裝成標準的過程
2.為標準過程的開始通知開始計時
3.為標準過程的結束通知結束計時
4.關閉冰箱,輸出計時結果

解決的幾種思路方法:
1、可以寫一個工具類,把重複的過程寫工具類裡
2、繼承一個類,執行相同的方法
3、動態代理解決
4、AOP

AOP底層就是通過動態代理實現的。(JDK動態代理,CGLIB動態代理)
即通過一定手段將不同服務的公共的縱向處理邏輯提取出來,統一實現。
二、AOP是什麼
AOP是面向切面程式設計,它是一種思想。交叉業務邏輯,系統級的服務是切面。把切面加入到主業務邏輯的過程就是織入
連線點:可以被切面織入的方法,通常業務介面的方法都是連線點。final方法不能是連線。
切入點:具體被織入的方法就是切入點。
目標物件:別增強的物件,主業務邏輯類的物件
通知Advice

通知是切面的一種實現,定義切入的時間
顧問Advisor顧問是切面的另一種實現,包裝了通知,能夠將通知以更為複雜的方式織入的目標物件。

可以說是OOP面向物件程式設計的一種完善和補充。面向物件更多的操作是縱向的(繼承,介面),這就導致一些需要在橫向上(即業務程式碼方法中的前後)嵌入的非核心程式碼得在每一個方法上都要去寫(比如日誌,許可權,異常處理等)。它們散佈在各方法的橫切面上,造成程式碼重複,也不利於各個模組的重用。
AOP就是為了解決這種難題而生的。在不修改程式碼的前提下,引入可以在執行期為類動態地新增一些方法或欄位

三、AOP能做什麼
1、降低模組之間的耦合度
2、使系統容易擴充套件
3、避免修改業務程式碼,避免引入重複程式碼,更好的程式碼複用
四、AOP怎麼用

/*
前置通知:某方法呼叫之前發出通知。
後置通知:某方法完成之後發出通知
返回後通知:方法正常返回後,呼叫通知。在方法呼叫後,正常退出發出通知
異常通知:丟擲異常後通知(After throwing advice) : 在方法丟擲異常退出時執行 的通知。在方法呼叫時,異常退出發出通知
環繞通知:通知包裹在被通知的方法的周圍知。

*/
@Aspect
@Component
public class LogAspect {
    private static final Logger logger=LoggerFactory.getLogger(LogAspect.class);
    @Before("execution(* com.hbu.toutiao.controller.SettingController.*(..))")
    public void beforeMethod(JoinPoint joinPoint){
        logger.info("方法執行之前");
    }
    @AfterReturning(value="execution(* com.hbu.toutiao.controller.SettingController.*(..))",returning = "result")
    public Object afterReturn(Object result){
        logger.info("執行返回後通知");
      return result+"返回後通知";
    }
    @After("execution(* com.hbu.toutiao.controller.SettingController.*(..))")
    public void afterMethod(){
        logger.info("執行後置通知方法執行之後");
    }

    @Around("poincut()")
    public  Object Around(ProceedingJoinPoint pjp) throws Throwable {
        logger.info("環繞執行之前");
        Object o=pjp.proceed();
        logger.info("環繞執行之後"+o);
        o="環繞通知:"+o;
        return  o;
    }
    @AfterThrowing(value = "execution(* com.hbu.toutiao.controller.SettingController.*(..))",throwing = "ex")
    public void exceptinMethod(Exception ex){
        logger.info("發生了異常"+ex.getMessage());
    }

    //定義一個切入點
    @Pointcut(value="execution(* com.hbu.toutiao.controller.SettingController.around(..))")
    public void poincut(){

    }
}