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 物件来执行,而从使用者的角度来看,就像是物件上平白增加了行为。