ITEEDU

Throw Advice

若 想要在例外发生时通知某些服务物件作某些事,您可以使用 Throws Advice,在 Spring 中想 要实作 Throws Advice,必须实作 org.springframework.aop.ThrowsAdvice 介面,然而这个介 面并没有定义任何的方法,它只是一个 标签介面(Tag interface),您可以在当中定义任意的 afterThrowing 方法名称,只要它是以下的形式:

afterThrowing([Method], [args],  [target], Throwable subclass)

方括号[]中的设定,例如 Method、args 与 target 等表示是可以省略的,方法中一定要的是 subclass,也就是这个参数必须是 Throwable 的子类别,在例外发生时,会检验所设定的 Throws Advice 中是否有符合例外类型的方法,如果有的话就通知它执行,以下是两个方法宣告的例子:

void afterThrowing(Throwable  throwable); 
void afterThrowing(Method  method, Object[] args, Object target, Throwable throwable);

您在方法上如果宣告不同的 Throwable 型态,则依例外发生类型的不同,会通知不同的方法,例 如 SomeException 会通知宣告有 SomeException 参数的方法,而 OtherException 会通知宣告有 OtherException 的方法。

注意到当例外发生时,Throw Advice 的任务只是呼叫对应的方法,您并不能在 Throws Advice 中将例外处理掉,在 Throw Advice 执行完毕后,原先的例外仍被传播至应用程式之中,Throw Advice 并不介入应用程式的例外处理,例外处理仍旧是应用程式本身所要负责的,如果您想要 在 Throw Advice 处理时中止应用程式的处理流程,作法是丢出其它的例外。

来看个 Throws Advice 的实际例子,首先定义 IHello 介面:

•      IHello.java
package onlyfun.caterpillar;
public interface IHello {
public void hello(String name) throws Throwable;
}

接着定义一个 HelloSpeaker 类别来实作 IHello 介面,并在 hello()方法当中模拟程式发生错误 时的例外丢出:

•      HelloSpeaker.java
package onlyfun.caterpillar;
public class HelloSpeaker implements IHello {
	public void hello(String name) throws Throwable { System.out.println("Hello, " + name);
		// 抱歉!程式错误!发生例外 XD
		throw new Exception("发生例外...");
	}
}

如果您需要在应用程式丢出例外时,介入 Throw Advice 以提供一些服务,,例如记录下一些例 外资讯,则您可以实作 ThrowAdvice 介面:

•      SomeThrowAdvice.java
package onlyfun.caterpillar;
import java.lang.reflect.Method; import java.util.logging.Level; import java.util.logging.Logger;
import org.springframework.aop.ThrowsAdvice;
public class SomeThrowAdvice implements ThrowsAdvice {
	private Logger logger = Logger.getLogger(this.getClass().getName());
	public void afterThrowing(Method method, Object[] args,
	Object target, Throwable subclass) {
		// 记录例外
		logger.log(Level.INFO,
		"Logging that a " + subclass + "Exception was thrown in " + method);
	}
}

接着在 Bean 定义档中写下以下的定义,以让 Throw Advice 在例外发生时提供记录服务:

•      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="someThrowAdvice" class="onlyfun.caterpillar.SomeThrowAdvice"/>
	<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>someThrowAdvice</value>
			</list>
		</property>
	</bean>
</beans>

可以撰写以下的程式来测试一下 Throw Advice 是否如预期般运作:

•      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) { ApplicationContext context =
		new FileSystemXmlApplicationContext( "beans-config.xml");
		IHello helloProxy =
		(IHello) context.getBean("helloProxy");
		try {
			helloProxy.hello("Justin");
		}
		catch(Throwable throwable) {
			// 应用程式的例外处理 System.err.println(throwable);
		}
	}
}

在程式中,应用程式本身定义了例外处理的逻辑,Throw Advice 不介面应用程式处理例外的逻 辑,Throw Advice 提供的是额外的记录服务。