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

Java 面向切面編程(AOP)實戰:AspectJ 註解式開發完整範例

     編輯:Java 相關知識

前言:為什麼需要 AOP?

在企業級開發中,**日誌記錄、事務管理、權限驗證、效能監控、快取、重試、錯誤處理**等橫切關注點散落在業務邏輯各處,導致程式碼重複、耦合度高、難以維護。AOP(Aspect-Oriented Programming)將這些橫切邏輯封裝為切面,透過切點精準織入目標方法,實現關注點分離。AspectJ 是 Java 生態最成熟、功能最強的 AOP 框架,支援註解式、XML、編譯期/載入期/執行期織入。

環境準備

<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjrt</artifactId>
    <version>1.9.21</version>
</dependency>
<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
    <version>1.9.21</version>
</dependency>

Spring Boot 專案只需 spring-boot-starter-aop,自動傳遞依賴並啟用 @EnableAspectJAutoProxy。

核心概念速覽

術語說明AspectJ 註解
切面橫切邏輯模組化單元@Aspect
切點定義「在哪裡」織入的謂詞@Pointcut
通知定義「何時、做什麼」@Before/@After/@AfterReturning/@AfterThrowing/@Around
連接點程式執行過程中可織入的具體點(方法呼叫、欄位存取、例外拋出等)—
引介為現有類動態新增介面/方法/欄位@DeclareParents

實戰範例:自定義註解 + 環繞通知實現方法執行時間監控

1. 定義標記註解

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MonitorTime {
    String value() default ""; // 業務標識
}

2. 切面類實現


@Aspect
@Component // Spring 管理
@Slf4j
public class MonitorAspect {

    @Pointcut("@annotation(com.example.demo.aop.MonitorTime)")
    public void monitorPointcut() {}

    @Around("monitorPointcut()")
    public Object monitor(ProceedingJoinPoint pjp) throws Throwable {
        long start = System.nanoTime();
        MethodSignature sig = (MethodSignature) pjp.getSignature();
        MonitorTime anno = sig.getMethod().getAnnotation(MonitorTime.class);
        String tag = anno.value().isEmpty() ? sig.getDeclaringTypeName() + "." + sig.getName() : anno.value();

        try {
            Object result = pjp.proceed(); // 執行目標方法
            long costMs = (System.nanoTime() - start) / 1_000_000;
            log.info("[Monitor] {} 耗時 {} ms", tag, costMs);
            return result;
        } catch (Exception e) {
            long costMs = (System.nanoTime() - start) / 1_000_000;
            log.error("[Monitor] {} 異常耗時 {} ms: {}", tag, costMs, e.getMessage(), e);
            throw e;
        }
    }
}

3. 業務方法使用


@Service
public class OrderService {
    @MonitorTime("下單流程")
    public Order createOrder(OrderDTO dto) {
        // 業務邏輯...
        return orderRepository.save(new Order(dto));
    }
}

進階切點表達式速查


// 執行 com.service 包下所有 public 方法
execution(public * com.service..*.*(..))

// 執行所有標記 @Transactional 的方法
@annotation(org.springframework.transaction.annotation.Transactional)

// 執行所有 Service 介面的實現類方法
execution(* com.service.*.*(..)) && target(com.service.BaseService)

// 組合:Service 層且非 getter/setter
execution(* com.service..*.*(..)) && !execution(* *.get*(..)) && !execution(* *.set*(..))

常見坑點與避坑指南

  1. 自我呼叫不生效:類內部 this.method() 繞過代理,AOP 失效。解法:注入自身 @Autowired Self self 或提取到別的 Bean。
  2. final 方法/類不可代理:JDK 動態代理需介面,CGLIB 代理類需非 final。Spring Boot 2.0+ 預設 proxy-target-class=true 使用 CGLIB。
  3. @Around 必須呼叫 pjp.proceed():否則目標方法不會執行;且需正確返回結果或拋出異常。
  4. 效能開銷:每次攔截產生 ProceedingJoinPoint、反射獲取註解。高頻熱點路徑(如每秒萬次)慎用,改用手動埋點或編譯期織入。
  5. 異常吞沒:@AfterThrowing 僅觀察,若需轉換異常請用 @Around 捕獲後重新拋出。

Spring AOP vs 純 AspectJ 選型

維度Spring AOP (執行期代理)AspectJ (編譯期/載入期織入)
支援連接點僅方法執行方法、建構子、欄位存取、靜態初始化等
部署複雜度零配置,啟動即用需 AJC 編譯器或 Java Agent (-javaagent:aspectjweaver.jar)
效能微小反射/代理開銷零執行期開銷,字節碼內聯
適用場景95% 業務系統極高頻熱點、領域模型引介、基礎設施框架

結語

AOP 是消除橫切關注點重複程式碼的利器。掌握 @Aspect、@Pointcut、五種通知類型、切點表達式語法,即可解決 90% 的 AOP 需求。記住:**切面要薄、職責單一、避免巢狀攔截、高頻路徑慎用**。配合自定義註解,能讓業務程式碼保持乾淨,同時獲得統一的可觀測性與治理能力。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved