AOP(面向切面編程)是 OOP 的補充。OOP 適合縱向關係(繼承),而橫切關係(日誌、事務、安全、緩存)分散在各業務模組中,導致代碼重複、耦合度高。AOP 通過「橫切」技術將這些通用行為封裝為可重用模組(切面),降低耦合,提升可維護性。
代理類與目標類實現同一介面,代理持有目標引用。缺點:每個目標類都需編寫專屬代理類,代碼膨脹。
public class ProxyHello implements IHello {
private IHello target;
public ProxyHello(IHello target) { this.target = target; }
public void sayHello(String str) {
Logger.start(); // 前置增強
target.sayHello(str);
Logger.end(); // 後置增強
}
}
利用 java.lang.reflect.InvocationHandler 與 Proxy.newProxyInstance() 在運行時動態生成代理類。單一代理類可服務多個目標類(需實現介面)。
public class DynamicProxy implements InvocationHandler {
private Object target;
public Object bind(Object target) {
this.target = target;
return Proxy.newProxyInstance(
target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
this
);
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Logger.start(); // 前置增強
Object result = method.invoke(target, args); // 執行目標方法
Logger.end(); // 後置增強
return result;
}
}
將「前置/後置增強」抽象為介面,代理類通過反射動態調用切面實現,實現代理邏輯與業務增強完全解耦。這就是 Spring AOP 的雛形。
public interface IAdvice { void before(Method m); void after(Method m); }
public class LoggingAdvice implements IAdvice { ... }
public class GenericProxy implements InvocationHandler {
private Object target, advice;
public Object bind(Object target, Object advice) { ... }
public Object invoke(Object proxy, Method method, Object[] args) {
Method before = advice.getClass().getMethod("before", Method.class);
before.invoke(advice, method);
Object result = method.invoke(target, args);
Method after = advice.getClass().getMethod("after", Method.class);
after.invoke(advice, method);
return result;
}
}
invoke() 中根據方法名判斷是否應用增強| 手寫框架概念 | Spring AOP 術語 | 說明 |
|---|---|---|
| 目標對象 | Target Object | 被代理的業務對象 |
| InvocationHandler 實現類 | MethodInterceptor | 環繞通知,核心攔截鏈 |
| IAdvice 介面 | Advice (Before/After/Around) | 具體增強邏輯 |
| 方法名匹配邏輯 | Pointcut | 切點表達式定義攔截位置 |
| Proxy.bind() | ProxyFactoryBean / @EnableAspectJAutoProxy | 代理創建與織入 |
Spring 默認:有介面用 JDK,無介面用 CGLIB。可通過 proxy-target-class="true" 強制使用 CGLIB。