Spring AOP 的最基礎實現方式是使用 ProxyFactoryBean 手動裝配代理、目標對象與通知。本文通過一個用戶管理業務場景,演示前置通知的配置與運行流程,幫助理解 AOP 底層機制。
// 數據訪問層
public interface UserDao {
void addUser(String username, String password);
void delUser(int id);
}
public class UserDaoImpl implements UserDao {
@Override public void addUser(String u, String p) { System.out.println(u + " 用戶添加成功"); }
@Override public void delUser(int id) { System.out.println("編號 " + id + " 用戶被刪除"); }
}
// 業務邏輯層
public interface UserBiz {
void addUser(String username, String password);
void delUser(int id);
}
public class UserBizImpl implements UserBiz {
private UserDao userDao;
public void setUserDao(UserDao userDao) { this.userDao = userDao; }
@Override public void addUser(String u, String p) { userDao.addUser(u, p); }
@Override public void delUser(int id) { userDao.delUser(id); }
}
import org.springframework.aop.MethodBeforeAdvice;
import java.lang.reflect.Method;
import org.apache.log4j.Logger;
public class LogAdvice implements MethodBeforeAdvice {
private static final Logger logger = Logger.getLogger(LogAdvice.class);
@Override
public void before(Method method, Object[] args, Object target) {
String cls = target.getClass().getName();
String mtd = method.getName();
logger.info("前置通知:" + cls + " 類的 " + mtd + " 方法開始執行");
}
}
<beans xmlns="https://www.springframework.org/schema/beans"
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- 目標對象 -->
<bean id="userDao" class="com.xue.dao.UserDaoImpl"/>
<bean id="userBiz" class="com.xue.dao.UserBizImpl">
<property name="userDao" ref="userDao"/>
</bean>
<!-- 通知 -->
<bean id="logAdvice" class="com.xue.aop.LogAdvice"/>
<!-- 代理工廠 -->
<bean id="ub" class="org.springframework.aop.framework.ProxyFactoryBean">
<!-- 代理接口 -->
<property name="proxyInterfaces" value="com.xue.dao.UserBiz"/>
<!-- 通知鏈 -->
<property name="interceptorNames">
<list><value>logAdvice</value></list>
</property>
<!-- 目標對象 -->
<property name="target" ref="userBiz"/>
</bean>
</beans>
public class Test {
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
UserBiz biz = (UserBiz) ctx.getBean("ub"); // 獲取代理對象
biz.addUser("zhangsan", "123");
biz.delUser(1);
}
}
[INFO ] [18:02:32] com.xue.aop.LogAdvice - 前置通知:com.xue.dao.UserBizImpl 類的 addUser 方法開始執行 zhangsan 用戶添加成功 [INFO ] [18:02:32] com.xue.aop.LogAdvice - 前置通知:com.xue.dao.UserBizImpl 類的 delUser 方法開始執行 編號 1 用戶被刪除
ProxyFactoryBean 實現 FactoryBean,getObject() 返回 JDK 動態代理(針對接口)或 CGLIB 代理(針對類)proxyInterfaces 指定代理實現的接口,target 指向被代理 BeaninterceptorNames 列表中的 Bean 必須實現 Advice 子接口(MethodBeforeAdvice、AfterReturningAdvice、ThrowsAdvice、MethodInterceptor 等)biz.addUser() 時,代理攔截 → 執行通知鏈 → 委派目標對象 → 返回結果| 通知類型 | 接口 | 執行時機 | 典型用途 |
|---|---|---|---|
| 前置通知 | MethodBeforeAdvice | 方法調用前 | 日志、權限檢查 |
| 後置通知 | AfterReturningAdvice | 方法正常返回後 | 結果增強、緩存更新 |
| 環繞通知 | MethodInterceptor | 完全控制調用 | 事務管理、性能監控 |
| 異常通知 | ThrowsAdvice | 方法拋出異常後 | 異常處理、告警 |
Spring 2.0+ 推薦使用 <aop:config> 或 @AspectJ 註解風格,配置更簡潔、可讀性更強。但理解 ProxyFactoryBean 有助於排查代理創建失敗、通知不生效等底層問題。
本示例展示了 Spring AOP 最原始的程式化配置方式,是掌握 AOP 核心概念的基石。