org.springframework.aop.support.ControlFlowPointcut
是Sping所提供的類別,作用為判斷在方法的呼叫堆疊中,某個指定類別的某方法中是否曾經要求您的目標物件執行某個動作,由於這是在執行時期才會確定是
否介入Advices,所以是Spring提供的動態Pointcut功能。
以 NameMatchMethodPointcutAdvisor
中的LogBeforeAdvice類別為例,您想要知道在onlyfun.caterpillar.Some類別中,是否曾經有某個方法中要求過您指定
的目標物件執行某些動作,如果有的話,則介入LogBeforeAdvice來提供日誌服務以記錄一些資訊,則您可以將Bean定義檔如下撰寫:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE beans PUBLIC "-//SPRING/DTD BEAN/EN" "http://www.springframework.org/dtd/spring-beans.dtd">
<beans> <bean id="some" class="onlyfun.caterpillar.Some"/> <bean id="logBeforeAdvice" class="onlyfun.caterpillar.LogBeforeAdvice"/> <bean id="helloFlowControlPointcut" class="org.springframework.aop.support.ControlFlowPointcut"> <constructor-arg> <value>onlyfun.caterpillar.Some</value> </constructor-arg> </bean> <bean id="helloAdvisor" class="org.springframework.aop.support.DefaultPointcutAdvisor"> <property name="advice"> <ref bean="logBeforeAdvice"/> </property> <property name="pointcut"> <ref bean="helloFlowControlPointcut"/> </property> </bean> <bean id="helloSpeaker" class="onlyfun.caterpillar.HelloSpeaker"/> <bean id="helloProxy" class="org.springframework.aop.framework.ProxyFactoryBean"> <property name="proxyInterfaces"> <value>onlyfun.caterpillar.IHello</value> </property> <property name="target"> <ref bean="helloSpeaker"/> </property> <property name="interceptorNames"> <list> <value>helloAdvisor</value> </list> </property> </bean> </beans>
在ControlFlowPointcut建構時,指定了onlyfun.caterpillar.Some類別,表示若在Some類別中的某個方法要求
了指定的目標物件(也就是helloSpeaker實例)執行某些動作,則應用Before
Advice(logBeforeAdvice)提供日誌的服務,Some類別可以簡單的如下撰寫:
package onlyfun.caterpillar;
import org.springframework.beans.BeansException; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware;
public class Some implements ApplicationContextAware { private IHello helloProxy;
public void setApplicationContext( ApplicationContext context) throws BeansException { helloProxy = (IHello) context.getBean("helloProxy"); } public void helloEverybody() { helloProxy.helloNewbie("Justin"); helloProxy.helloMaster("caterpillar"); } }
為了方便您取得ApplicationContext以獲得helloSpeaker的代理物件,Some類別實現了
org.springframework.context.ApplicationContextAware介面,接著可以撰寫一個簡單的程式來測試一下
ControlFlowPointcut的運作,如下所示:
package onlyfun.caterpillar;
import org.springframework.context.ApplicationContext; import org.springframework.context. support.FileSystemXmlApplicationContext;
public class SpringAOPDemo { public static void main(String[] args) { ApplicationContext context = new FileSystemXmlApplicationContext( "beans-config.xml"); Some some = (Some) context.getBean("some"); if(args.length > 0 && "run".equals(args[0])) { some.helloEverybody(); } else { System.out.println("作其它的事情..."); } } }
其餘未列出的程式,都與 NameMatchMethodPointcutAdvisor 中的程式相同,如果您執行程式時沒有提供"run"引數,則會出現"作其它的事情"的文字訊息,這是因為沒有執行Some實例的helloEverybody(),在呼叫堆疊中並不符合所指定的:ome類別的某方法曾要求helloSpeaker實例執行某些動作。
如果您執行程式時提供了"run"引數,則會呼叫Some類別的helloEverybody()方法,方法中要求helloSpeaker的代理物件執
行helloNewbie()與helloMaster()方法,符合Bean定義檔中指定的內容,因而會應用LogBeforeAdvice來提供服務
訊息。
動態Pointcut的問題就是在於效能上的付出,由於呼叫堆疊的判斷是在執行時期進行,所以執行時會很慢,在不同的JDK上可能會有5到10倍的效能延緩,因此建議在可能的情況下,儘量使用靜態Pointcut。
|