ITEEDU

DelegatingIntroductionInterceptor

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