org.springframework.aop.support.DelegatingIntroductionInterceptor 是Spring AOP中為IntroductionInterceptor介面所提供的實作類別,您可以直接繼承這個類別,並添加您自己希望為目標物件增加的行為,並可 以帶有物件自己的狀態,例如讓物件攜帶有「是」、「否」鎖定的狀態, DelegatingIntroductionInterceptor已經為您實作了大部份的細節。
舉個例子來說,假設您的系統中已經有這樣的類別:
- ISome.java
package onlyfun.caterpillar;
public interface ISome {
public void setSome(String some);
public String getSome();
}
- Some.java
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介面,上面定義的是您想添加至目標物件的操作方法:
- ILockable.java
package onlyfun.caterpillar;
public interface ILockable {
public void lock();
public void unlock();
public boolean isLocked();
}
接著繼承DelegatingIntroductionInterceptor類別,並同時實作ILockable介面:
- LockIntroduction.java
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定義檔的內容可以如下撰寫:
- beans-config.xml
<?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>
來撰寫一個簡單的測試程式,看看如何利用增加的行為來進行物件鎖定:
- SpringAOPDemo.java
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物件來執行,而從使用者的角度來看,就像是物件上平白增加了行為。