org.springframework.aop.support.DelegatingIntroductionInterceptor
是Spring
AOP中為IntroductionInterceptor介面所提供的實作類別,您可以直接繼承這個類別,並添加您自己希望為目標物件增加的行為,並可
以帶有物件自己的狀態,例如讓物件攜帶有「是」、「否」鎖定的狀態,
DelegatingIntroductionInterceptor已經為您實作了大部份的細節。
舉個例子來說,假設您的系統中已經有這樣的類別:
package onlyfun.caterpillar;
public interface ISome { public void setSome(String some); public String getSome(); }
package onlyfun.caterpillar;
public class Some implements ISome { private String some; public void setSome(String some) { this.some = some; } public String getSome() { return some; } }
在不修改Some.java程式內容的情況下,您希望可以增加一個locked的boolean型態資料成員,並可以增加可操作的lock()與
unlock()方法來設定locked成員為true或false,如果locked被設定為true,則鎖定setSome()方法無法被呼叫,也就
是將物件鎖定為不可變動(Immutable)。
您可以先定義一個ILockable介面,上面定義的是您想添加至目標物件的操作方法:
package onlyfun.caterpillar;
public interface ILockable { public void lock(); public void unlock(); public boolean isLocked(); }
接著繼承DelegatingIntroductionInterceptor類別,並同時實作ILockable介面:
package onlyfun.caterpillar;
import org.springframework.aop. support.DelegatingIntroductionInterceptor; import org.aopalliance.intercept.MethodInvocation; import org.springframework.aop. framework.AopConfigException;
public class LockIntroduction extends DelegatingIntroductionInterceptor implements ILockable { private boolean locked;
public Object invoke(MethodInvocation invocation) throws Throwable { // locked 為true下不能呼叫set方法 if (isLocked() && invocation.getMethod(). getName().indexOf("set") == 0) { throw new AopConfigException( "物件被鎖定!!"); } return super.invoke(invocation); } public void lock() { locked = true; }
public void unlock() { locked = false; }
public boolean isLocked() { return locked; } }
新增的行為是,當物件使用lock()方法設定locked為true時鎖定物件,如果此時有其它物件打算呼叫set方法則丟出例外,通知呼叫者物件已是在鎖定狀態,至於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="lockIntroduction" class="onlyfun.caterpillar.LockIntroduction"/> <bean id="lockAdvisor" class="org.springframework.aop.support.DefaultIntroductionAdvisor"> <constructor-arg index="0"> <ref bean="lockIntroduction"/> </constructor-arg> <constructor-arg index="1"> <value>onlyfun.caterpillar.ILockable</value> </constructor-arg> </bean> <bean id="proxyFactoryBean" class="org.springframework.aop.framework.ProxyFactoryBean"> <property name="proxyInterfaces"> <value>onlyfun.caterpillar.ISome</value> </property> <property name="target"> <ref bean="some"/> </property> <property name="interceptorNames"> <list> <value>lockAdvisor</value> </list> </property> </bean> </beans>
來撰寫一個簡單的測試程式,看看如何利用增加的行為來進行物件鎖定:
package onlyfun.caterpillar;
import org.springframework.context.ApplicationContext; import org.springframework.context. support.FileSystemXmlApplicationContext;
public class SpringAOPDemo { public static void main(String[] args) throws Exception { ApplicationContext context = new FileSystemXmlApplicationContext( "beans-config.xml"); ISome some = (ISome) context.getBean("proxyFactoryBean"); // 物件沒有被鎖定,可以呼叫set方法 some.setSome("justin"); System.out.println(some.getSome()); try { // 物件被鎖定 ((ILockable) some).lock(); // 無法呼叫set方法,丟出例外 some.setSome("momor"); // 由於會丟出例外,所以下面的這行程式無法被執行 System.out.println(some.getSome()); } catch(Throwable e) { e.printStackTrace(); } // Object is unlocked. ((ILockable) some).unlock(); // It's ok to use setter again. some.setSome("momor"); System.out.println(some.getSome()); } }
執行時在some所參考的物件上,可以呼叫新添加的lock()方法來進行鎖定,當some所參考的物件被鎖定時,則呼叫set方法會丟出例外,可以呼叫unlock()方法解除鎖定。
事實上,Some類別上並沒有真正增加行為,從以上兩個專案的例子中可以看出,Introduction事實上是利用委託的方式,當呼叫非Some類別上
所定義的方法時,在代理物件中再委託Introduction物件來執行,而從使用者的角度來看,就像是物件上平白增加了行為。
|