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

Spring 無介面代理實現 AOP:基於 CGLIB 的實戰範例

     編輯:Java 相關知識

概述

Spring AOP 支援兩種代理方式:JDK 動態代理 (需實作介面) 與 CGLIB 代理 (無需介面,直接代理類)。本文透過完整範例示範如何使用 CGLIB 實現無介面的 AOP 切面編程,針對 UserManagerImpl 類的 add* 方法織入安全檢查邏輯。

核心類別設計

目標類:UserManagerImpl

未實作任何介面的普通 POJO,包含 addUser 與 deleteUser 兩個方法:

package com.rx.spring.cglib;

public class UserManagerImpl {
    public void addUser(String username, String password) {
        System.out.println("-------UserManagerImpl.addUser()----------");
    }
    public void deleteUser(int id) {
        System.out.println("-------UserManagerImpl.deleteUser()----------");
    }
}

切面類:SecurityHandler

定義前置通知 checkSecurity,接收 JoinPoint 參數以獲取方法引數、方法名等資訊:

package com.rx.spring.cglib;

import org.aspectj.lang.JoinPoint;

public class SecurityHandler {
    private void checkSecurity(JoinPoint joinPoint) {
        Object[] args = joinPoint.getArgs();
        for (int i = 0; i < args.length; i++) {
            System.out.println(args[i]);
        }
        System.out.println(joinPoint.getSignature().getName());
        System.out.println("----------checkSecurity()---------------");
    }
}

客戶端測試類

透過 ClassPathXmlApplicationContext 載入配置,獲取 userManager bean 並呼叫方法驗證 AOP 效果:

package com.rx.spring.cglib;

import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Client {
    public static void main(String[] args) {
        BeanFactory factory = new ClassPathXmlApplicationContext("applicationContextCglib.xml");
        UserManagerImpl userManager = (UserManagerImpl) factory.getBean("userManager");
        userManager.addUser("abc", "123");
        System.out.println("testing");
        userManager.deleteUser(1);
    }
}

Spring AOP 配置檔 (applicationContextCglib.xml)

關鍵配置點:

  • 啟用 CGLIB 代理:<aop:aspectj-autoproxy proxy-target-class="true"/> (範例中被註解,但實際需啟用或透過 <aop:config> 隱含支援)
  • 定義切面:<aop:config> 內宣告 <aop:aspect> 關聯 securityHandler bean
  • 切點運算式:execution(* com.rx.spring.cglib.UserManagerImpl.add*(..)) 匹配所有以 add 開頭的方法
  • 前置通知:<aop:before method="checkSecurity" pointcut-ref="allAddMethod"/>
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="https://www.springframework.org/schema/beans"
 xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
 xmlns:aop="https://www.springframework.org/schema/aop"
 xmlns:tx="https://www.springframework.org/schema/tx"
 xsi:schemaLocation="
 https://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans-2.0.xsd
 https://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop-2.0.xsd
 https://www.springframework.org/schema/tx https://www.springframework.org/schema/tx/spring-tx-2.0.xsd">

<!-- 啟用 CGLIB 代理,proxy-target-class="true" 為關鍵 -->
<aop:aspectj-autoproxy proxy-target-class="true"/>

<bean id="securityHandler" class="com.rx.spring.cglib.SecurityHandler"/>
<bean id="userManager" class="com.rx.spring.cglib.UserManagerImpl"/>

<aop:config>
 <aop:aspect id="security" ref="securityHandler">
 <aop:pointcut id="allAddMethod" expression="execution(* com.rx.spring.cglib.UserManagerImpl.add*(..))"/>
 <aop:before method="checkSecurity" pointcut-ref="allAddMethod"/>
 </aop:aspect>
</aop:config>

</beans>

執行結果與驗證

運行 Client.main() 後,控制台輸出:

abc
123
addUser
----------checkSecurity()---------------
-------UserManagerImpl.addUser()----------
testing
-------UserManagerImpl.deleteUser()----------

可見:

  1. addUser 呼叫前,checkSecurity 先執行,印出引數 abc、123 及方法名
  2. deleteUser 不匹配切點,未觸發通知

關鍵技術點總結

項目說明
代理模式CGLIB (繼承目標類生成子類),無需介面
啟用方式proxy-target-class="true" 或 <aop:config> 內隱含
切點運算式AspectJ 語法,execution(* pkg.Class.method*(..))
通知類型前置通知 (aop:before),亦支援後置、環繞、拋出、返回通知
JoinPoint提供方法簽名、引數、目標物件等上下文資訊

常見問題與注意事項

  • final 方法無法代理:CGLIB 透過覆寫方法實現攔截,final 方法將被忽略
  • 構造函數攔截限制:CGLIB 無法攔截構造函數呼叫
  • 效能考量:CGLIB 生成類的開銷略大於 JDK 代理,但避免介面定義的束縛
  • Spring Boot 環境:預設已啟用 proxy-target-class=true,無額外配置即可使用 CGLIB

Spring CGLIB AOP 執行流程圖

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