首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 綜合教學

Spring AOP 核心概念深度解析:切面、通知、切點、織入與代理機制全面指南

     編輯:Java 綜合教學

AOP 核心動機:橫切關注點分離

日志、事務、安全、緩存等功能分散在各業務模塊中,導致代碼耦合、重複、難維護。AOP 將這些橫切關注點 模塊化為切面,通過聲明式方式織入業務邏輯,實現關注點分離。

五大核心概念術語表

術語英文核心含義
通知Advice切面具體執行的邏輯(做什麼、何時做)
連接點Join Point程序執行中可插入切面的點(方法調用、異常拋出、字段訪問)
切點Pointcut匹配連接點的條件表達式,定義「在何處」織入
切面Aspect通知 + 切點 = 完整切面定義
引入Introduction為現有類動態添加方法/字段/接口實現
織入Weaving將切面應用到目標對象創建代理的過程

五種通知類型與執行時機

@Aspect
public class LoggingAspect {

    @Pointcut("execution(* com.example.service.*.*(..))")
    public void serviceLayer() {}

    // 1. 前置通知:方法執行前
    @Before("serviceLayer()")
    public void before(JoinPoint jp) {
        log.info("Enter: {}", jp.getSignature());
    }

    // 2. 後置通知:方法正常返回後
    @AfterReturning(pointcut = "serviceLayer()", returning = "result")
    public void afterReturn(JoinPoint jp, Object result) {
        log.info("Exit: {} -> {}", jp.getSignature(), result);
    }

    // 3. 異常通知:方法拋出異常後
    @AfterThrowing(pointcut = "serviceLayer()", throwing = "ex")
    public void afterThrow(JoinPoint jp, Exception ex) {
        log.error("Exception: {}", ex.getMessage());
    }

    // 4. 最终通知:無論正常/異常都執行 (finally)
    @After("serviceLayer()")
    public void afterFinally(JoinPoint jp) {
        // 清理資源、釋放鎖等
    }

    // 5. 環繞通知:完全控制方法執行 (最強大、最複雜)
    @Around("serviceLayer()")
    public Object around(ProceedingJoinPoint pjp) throws Throwable {
        long start = System.currentTimeMillis();
        try {
            Object result = pjp.proceed(); // 繼續執行目標方法
            return result;
        } finally {
            log.info("Duration: {}ms", System.currentTimeMillis() - start);
        }
    }
}

Spring AOP 代理機制原理

Spring AOP 代理結構圖

  • 運行期織入:基於動態代理 (JDK Proxy / CGLIB),啟動時創建代理 Bean
  • JDK 動態代理:目標實現接口 → 生成實現同接口的代理類
  • CGLIB 代理:目標無接口 → 生成繼承目標類的子類代理
  • 攔截鏈:調用代理方法 → 通知鏈執行 → 目標方法 → 通知鏈返回

Spring 支持的四種 AOP 風格

  1. @AspectJ 註解風格 (推薦):標準化、IDE 支持好、功能最全
  2. Schema XML 風格:<aop:config>、<aop:aspect> 純 XML 聲明
  3. 經典代理風格:ProxyFactoryBean 程序化配置,歷史遺留
  4. 注入式 AspectJ:編譯期/類加載期織入,需 AJC 編譯器,功能最強 (支持字段/構造器切點)

切點表達式速查

execution(public * com.example..*.*(..))          // 包及子包所有公共方法
execution(* *..service.*.*(..))                    // service 包下所有方法
@annotation(com.example.Loggable)                  // 帶特定註解的方法
this(com.example.ServiceInterface)                 // 代理實現指定接口
target(com.example.ServiceImpl)                    // 目標對象類型
args(java.io.Serializable)                         // 參數類型匹配
@within(org.springframework.transaction.annotation.Transactional) // 類級註解
bean(*Service)                                     // Bean 名稱模式 (Spring 專有)

關鍵限制與最佳實踐

  • 僅支持方法連接點:無字段/構造器切點 (需全 AspectJ)
  • 自調用不生效:同類內部方法調用繞過代理,需注入自身或重構
  • final/private 方法不可代理:無法被重寫/攔截
  • 性能考量:環繞通知慎用,避免過度 AOP 導致調試困難
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved