操作增強(Advised)物件
無論如何建立 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、interceptor 或其他通知型別返回一個 Advisor
。如果您添加了一個 Advisor
,則此索引處返回的 advisor 就是您新增的物件。如果您添加了 interceptor 或其他通知型別,Spring 會將其封裝在一個 pointcut 始終返回 true
的 advisor 中。因此,如果您添加了一個 MethodInterceptor
,則此索引處返回的 advisor 是一個 DefaultPointcutAdvisor
,它返回您的 MethodInterceptor
和匹配所有類和方法的 pointcut。
addAdvisor()
方法可用於新增任何 Advisor
。通常,持有 pointcut 和 advice 的 advisor 是通用的 DefaultPointcutAdvisor
,您可以將其用於任何 advice 或 pointcut(但不適用於引介)。
預設情況下,即使代理已建立,也可以新增或移除 advisor 或 interceptor。唯一的限制是無法新增或移除引介 advisor,因為工廠中現有的代理不會顯示介面更改。(您可以從工廠獲取一個新代理來避免此問題。)
以下示例演示了將 AOP 代理強制轉換為 Advised
介面以及檢查和操作其通知:
-
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)
在生產環境中修改業務物件的通知是否明智,這一點值得商榷,儘管無疑存在合法的用例。但是,這在開發中(例如,在測試中)可能非常有用。我們有時發現能夠以 interceptor 或其他通知的形式新增測試程式碼非常有用,從而進入我們想要測試的方法呼叫內部。(例如,通知可以進入為該方法建立的事務內部,也許在標記事務回滾之前執行 SQL 以檢查資料庫是否已正確更新。) |
根據建立代理的方式,您通常可以設定一個 frozen
標誌。在這種情況下,Advised
介面的 isFrozen()
方法返回 true
,任何透過新增或移除來修改通知的嘗試都會導致 AopConfigException
。在某些情況下,凍結增強(advised)物件的狀態很有用(例如,防止呼叫程式碼移除安全 interceptor)。