操作被通知物件
無論您如何建立 AOP 代理,您都可以透過使用 org.springframework.aop.framework.Advised 介面來操縱它們。任何 AOP 代理都可以強制轉換為此介面,無論它實現哪些其他介面。此介面包含以下方法:
-
Java
-
Kotlin
Advisor[] getAdvisors();
void addAdvice(Advice advice) throws AopConfigException;
void addAdvice(int pos, Advice advice) throws AopConfigException;
void addAdvisor(Advisor advisor) throws AopConfigException;
void addAdvisor(int pos, Advisor advisor) throws AopConfigException;
int indexOf(Advisor advisor);
boolean removeAdvisor(Advisor advisor) throws AopConfigException;
void removeAdvisor(int index) throws AopConfigException;
boolean replaceAdvisor(Advisor a, Advisor b) throws AopConfigException;
boolean isFrozen();
fun getAdvisors(): Array<Advisor>
@Throws(AopConfigException::class)
fun addAdvice(advice: Advice)
@Throws(AopConfigException::class)
fun addAdvice(pos: Int, advice: Advice)
@Throws(AopConfigException::class)
fun addAdvisor(advisor: Advisor)
@Throws(AopConfigException::class)
fun addAdvisor(pos: Int, advisor: Advisor)
fun indexOf(advisor: Advisor): Int
@Throws(AopConfigException::class)
fun removeAdvisor(advisor: Advisor): Boolean
@Throws(AopConfigException::class)
fun removeAdvisor(index: Int)
@Throws(AopConfigException::class)
fun replaceAdvisor(a: Advisor, b: Advisor): Boolean
fun isFrozen(): Boolean
getAdvisors() 方法為新增到工廠的每個 Advisor、攔截器或其他 Advice 型別返回一個 Advisor。如果您添加了一個 Advisor,此索引處返回的 Advisor 就是您新增的物件。如果您添加了一個攔截器或其他 Advice 型別,Spring 會將其包裝在一個 Advisor 中,該 Advisor 的切點始終返回 true。因此,如果您添加了一個 MethodInterceptor,此索引處返回的 Advisor 是一個 DefaultPointcutAdvisor,它返回您的 MethodInterceptor 和一個匹配所有類和方法的切點。
addAdvisor() 方法可用於新增任何 Advisor。通常,持有切點和 Advice 的 Advisor 是通用的 DefaultPointcutAdvisor,您可以將其與任何 Advice 或切點一起使用(但不能用於引入)。
預設情況下,即使在建立代理之後,也可以新增或刪除 Advisor 或攔截器。唯一的限制是無法新增或刪除引入 Advisor,因為工廠中現有代理不會顯示介面更改。(您可以從工廠獲取一個新代理來避免此問題。)
以下示例演示了將 AOP 代理轉換為 Advised 介面並檢查和操縱其 Advice:
-
Java
-
Kotlin
Advised advised = (Advised) myObject;
Advisor[] advisors = advised.getAdvisors();
int oldAdvisorCount = advisors.length;
System.out.println(oldAdvisorCount + " advisors");
// Add an advice like an interceptor without a pointcut
// Will match all proxied methods
// Can use for interceptors, before, after returning or throws advice
advised.addAdvice(new DebugInterceptor());
// Add selective advice using a pointcut
advised.addAdvisor(new DefaultPointcutAdvisor(mySpecialPointcut, myAdvice));
assertEquals("Added two advisors", oldAdvisorCount + 2, advised.getAdvisors().length);
val advised = myObject as Advised
val advisors = advised.advisors
val oldAdvisorCount = advisors.size
println("$oldAdvisorCount advisors")
// Add an advice like an interceptor without a pointcut
// Will match all proxied methods
// Can use for interceptors, before, after returning or throws advice
advised.addAdvice(DebugInterceptor())
// Add selective advice using a pointcut
advised.addAdvisor(DefaultPointcutAdvisor(mySpecialPointcut, myAdvice))
assertEquals("Added two advisors", oldAdvisorCount + 2, advised.advisors.size)
| 在生產環境中修改業務物件上的 Advice 是否明智(無雙關之意)值得商榷,儘管毫無疑問存在合法的用例。然而,這在開發中可能非常有用(例如,在測試中)。我們有時發現能夠以攔截器或其他 Advice 的形式新增測試程式碼非常有用,可以進入我們想要測試的方法呼叫中。(例如,Advice 可以進入為該方法建立的事務中,也許可以執行 SQL 來檢查資料庫是否正確更新,然後將事務標記為回滾。) |
根據您建立代理的方式,您通常可以設定一個 frozen 標誌。在這種情況下,Advised 介面的 isFrozen() 方法返回 true,並且任何透過新增或刪除修改 Advice 的嘗試都會導致 AopConfigException。凍結被通知物件狀態的能力在某些情況下很有用(例如,防止呼叫程式碼刪除安全攔截器)。