操作 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、攔截器或其他 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
。在某些情況下,凍結 advised 物件狀態的能力非常有用(例如,防止呼叫程式碼移除安全性攔截器)。