對AOP切面的一些整理與理解

  首先上一張AOP的圖示

一:幾個重要的概念
  1> 切面:橫切關注點(跨越應用程序多個模塊的功能)被模塊化的特殊對象[驗證切面,日誌切面]
  2> 通知:切面中的每一個方法
  3> 目標:被通知的方法(業務邏輯中的方法)
  4> 代理(proxy):向目標對象應用通知之後創建的對象
  5> 連接點:程序執行前的某個特定位置(具體的物理存在):如某個方法調用前,調用後,方法拋出異常後等。連接點由兩個信息確定:方法表示的程序執行點相對點表示的方位。
  6> 切點:每個類會有多個連接點(看不到摸不到,非具體物理存在)[通過切點可以定位到很多個連接點]即:連接點是程序類中客觀存在的事務。AOP通過切點定位到特定的鏈接點。類比:連接點相當於數據庫中的記錄,切點相當於查詢條件。切點和連接點不是一一對應的關係,一個切點匹配多個連接點,切點通過接口進行描述,使用類和方法作爲連接點的查詢條件。

二:Spring AOP
  1)加入jar包
  2)在配置文件中加入aop的命名空間(namespace),完整命名空間如下:
    <?xml version="1.0" encoding="GB18030"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xmlns:aop="http://www.springframework.org/schema/aop"
           xsi:schemaLocation="http://www.springframework.org/schema/beans
                               http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
                               http://www.springframework.org/schema/aop
                               http://www.springframework.org/schema/aop/spring-aop-2.0.xsd">
    </beans>
  3)基於註解的方式
     1.在配置文件中加入該配置
     <!-- 啓動用JDK動態代理完成對Aop的支持,支持註解的形式 -->
     <aop:aspectj-autoproxy></aop:aspectj-autoproxy> 
     
     2.配置切面及業務邏輯對象  
     但在 spring4.0 可以配置自動掃描的包,只需要包命明確即可
     <context:component-scan   base-package="" />
    
     spring2.0不具備該屬性,正確配置如下:1》切面 2》業務邏輯對象
     <!-- 切面 -->
     <bean id="checkAspect" class="com.inspur.aop.impl.CheckAspect"></bean>
     <!-- 業務邏輯對象 -->
     <bean id="calculator"  class="com.inspur.aop.impl.CalculatorLightImpl"> 
     </bean> 

     3.通過代碼進行展示 testspring2
    package com.inspur.aop.impl;
    import java.util.Arrays;
    import java.util.List;
    import org.aspectj.lang.JoinPoint;
    import org.aspectj.lang.annotation.Aspect;
    import org.aspectj.lang.annotation.Before;
    import org.aspectj.lang.annotation.Pointcut;
    @Aspect
    public class CheckAspect {
         /**
          * 切入點 做標識使用 特徵:private void 方法名(){ }
          */
         @Pointcut("execution(* com.inspur.aop.impl.*.*(..))")
         public void allCalMethod() {}

         @Before("allCalMethod()")
         public void check(JoinPoint joinPoint) {
          //兩種方法獲取參數的值
          /*// 取得參數的值
             Object[] objects = joinPoint.getArgs();
             if (objects != null && objects.length > 0) {
                 for (Object arg : objects) {
                     System.out.println(arg);
                 }
          }*/
           String methodName = joinPoint.getSignature().getName();
           System.out.println(" methodName " + methodName);
           List<Object> args = Arrays.asList(joinPoint.getArgs());
           System.out.println(" the method " + methodName + " begin with " + args);
        }
    }
    
    另:切入點其實可以不進行書寫,僅作爲標識使用。
        如不寫,則在通知(@befor,@after等)中寫進執行語句
            即@Before("execution(* com.inspur.aop.impl.*.*(..))")
        也可以實現作爲切面的功能。
面向切面編程是面向對象編程的一種改進,他的出現在於解決兩大問題:(詳見testSpring2項目)
  1.代碼混亂:越來越多的非業務需求(日誌和校驗等)加入後,原有的業務方法急劇膨脹, 每個方法在處理核心業務邏輯時,還必須兼顧其他多個關注點。
  2.代碼分散:以日誌需求爲例,只是爲了滿足這個單一的需求,就不得不在多個模塊 裏面多次重複相同的日誌代碼。如果日誌代碼發生改變,也必須修改所有模板。[核心代碼需要寫入衆多的輸出語句,代碼冗餘及維護困難等各種問題]

從上述代碼引申三個問題:
1.切入點的定義[execution:執行]
·任意公共方法的執行
  execution(public * *(..))
·任意一個以‘set’開始的方法的執行
  execution(* set*(..))
·AccountService接口的任意方法的執行
execution(* com.xyz.service.AccountService.(..))
·定義在service包裏任意方法的執行(最爲常用)
  execution(* com.xyz.service.*.*(..))
·定義在service包或子包裏任意方法的執行
 )
2.Adivce,通知的類型
 ·前置通知 @Before
 ·後置通知 @After
 ·返回後通知
 ·異常拋出後通知
 ·環繞通知
3.JoiPoint方法:任何一個增強方法都可以通過將第一個入參聲明爲 JoinPoint 訪問到連接點上下文的信息。(簡化日誌)
  AspectJ 使用 org.aspectj.lang.JoinPoint 接口表示目標類連接點對象,如果是環繞增強時,使用org.aspectj.lang.ProceedingJoinPoint 表示連接點對象,該類是 JoinPoint 的子接口。任何一個增強方法都可以通過將第一個入參聲明爲 JoinPoint 訪問到連接點上下文的信息。我們先來了解一下這兩個接口的主要方法: 
1) JoinPoint 
 java.lang.Object[] getArgs():獲取連接點方法運行時的入參列表; 
 Signature getSignature() :獲取連接點的方法簽名對象; 
 java.lang.Object getTarget() :獲取連接點所在的目標對象; 
 java.lang.Object getThis() :獲取代理對象本身; 
2) ProceedingJoinPoint 
   ProceedingJoinPoint繼承JoinPoint子接口,它新增了兩個用於執行連接點方法的方法: 
 java.lang.Object proceed() throws java.lang.Throwable:通過反射執行目標對象的連接點處的方法; 
 java.lang.Object proceed(java.lang.Object[] args) throws java.lang.Throwable:通過反射執行目標對象連接點處的方法,不過使用新的入參替換原來的入參。
  上面的代碼提到了兩種獲取參數的方法,重點記住各個方法的類型及遍歷的方式。

發佈了51 篇原創文章 · 獲贊 3 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章