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

Spring AOP 註解完整指南:從配置到實戰應用

     編輯:Java 綜合教學

Spring AOP 核心概念與註解詳解

面向切面編程(AOP)是 Spring 框架的核心功能之一,它允許開發者將橫切關注點(如日誌、事務、安全)與業務邏輯分離。Spring AOP 基於代理模式,支援五種通知類型:@Before(前置)、@After(後置)、@Around(環繞)、@AfterReturning(返回後)、@AfterThrowing(拋出異常後)。

環境配置:Maven 依賴與 XML 啟用

必要依賴

<!-- Spring AOP + AspectJ -->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-aop</artifactId>
    <version>${spring.version}</version>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-aspects</artifactId>
    <version>${spring.version}</version>
</dependency>
<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>
<dependency>
    <groupId>cglib</groupId>
    <artifactId>cglib</artifactId>
    <version>3.3.0</version> <!-- 建議升級版本 -->
</dependency>

啟用 AspectJ 自動代理

<aop:aspectj-autoproxy expose-proxy="true"/>

在 applicationContext.xml 中加入上述配置,即可啟用基於註解的 AOP 功能。expose-proxy="true" 允許通過 AopContext.currentProxy() 獲取當前代理對象。

切面類實戰:多種切點表達式與通知

@Component
@Aspect
public class CustomAspect {

    // 1. execution 表達式:攔截 services 包及子包下所有以 for 開頭的方法
    @Pointcut("execution(* com.maven.project.services..for*(..))")
    public void query() {}

    // 2. 註解驅動切點:攜帶 @QuerySystem 註解的方法
    @Pointcut("@annotation(com.maven.project.web.customAnnotations.QuerySystem)")
    public void loginTimeOut() {}

    // 前置通知
    @Before("query()")
    public void queryBefore(JoinPoint joinPoint) {
        System.out.println("=======query start @Before ====方法名稱:" + joinPoint.getSignature().getName());
    }

    // 後置通知
    @After("query()")
    public void queryAfter(JoinPoint joinPoint) {
        System.out.println("=======query end @After ====方法名稱:" + joinPoint.getSignature().getName());
    }

    // 環繞通知:需手動調用 proceed() 並返回結果
    @Around("query()")
    public Object queryAround(ProceedingJoinPoint joinPoint) throws Throwable {
        System.out.println("=======query start @Around ====方法名稱:" + joinPoint.getSignature().getName());
        Object result = joinPoint.proceed(); // 必須返回結果
        System.out.println("=======query end @Around ====方法名稱:" + joinPoint.getSignature().getName());
        return result;
    }

    // 統計方法執行時間
    @Around("loginTimeOut()")
    public Object times(ProceedingJoinPoint joinPoint) throws Throwable {
        long start = System.currentTimeMillis();
        Object result = joinPoint.proceed();
        long end = System.currentTimeMillis();
        System.out.println("======= 登陸耗時:" + (end - start) + "ms ====方法名稱:" + joinPoint.getSignature().getName());
        return result;
    }
}

自定義註解與使用示例

@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface QuerySystem {
    String description() default "";
}

控制層引用

@RequestMapping("/login")
@QuerySystem(description = "用戶登錄接口")
public void login(HttpServletRequest request, HttpServletResponse response) {
    // 業務邏輯
}

Execution 表達式深度解析

execution(modifiers? return-type declaring-type? method-name(param) throws?)

  • 返回類型:* 表示任意類型
  • 包名:com.maven.project.services.. 表示該包及所有子包
  • 類名:* 表示所有類
  • 方法名:for* 表示以 for 開頭的方法
  • 參數:(..) 表示任意參數

常用模式速查表

表達式匹配範圍
execution(public * *(..))所有 public 方法
execution(* *To(..))所有以 To 結尾的方法
execution(* com.baobaotao.Waiter.*(..))Waiter 接口所有方法
execution(* com.baobaotao..*(..))com.baobaotao 包及子包所有類的所有方法
execution(* joke(String,..))第一個參數為 String 的 joke 方法

最佳實踐建議

  1. 優先使用 @Annotation 切點,業務語義清晰,重構安全
  2. 環繞通知必須返回 joinPoint.proceed() 結果,否則目標方法返回值丟失
  3. 避免在切面中處理過重業務邏輯,保持切面輕量
  4. 生產環境建議關閉 expose-proxy 以提升性能
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved