Spring AOP Advices
Advices实现了Aspect的真正逻辑,具体来说在java中就是一个类或更细粒度的设计成一个方法(由一个类集中管理多个Advices)。按织入Targets的时机不同,spring提供了几种不同的Advices,如:Before Advices、After Advices、Around Advices、Throw Advice。
一、Before Advices
Before Advices会在目标对象的方法执行之前被调用,可以调用org.springframework.aop.MethodBeforeAdvice接口来实现Before Advice的逻辑,该接口的定义如下:
public interface MethodBefore extends BeforeAdvice{
void before(Method method,Object[] args,Object target) throws Throwable;
}
BeforeAdvice继承自Advice接口,而这两个都是标签接口。没有任何方法。
before()方法会在目标对象(Target)所指定的方法执行之前被执行,可以取得被执行的Method实例、参数对象数组以及目标对象。
例子:
public interface IHello{
public void hello(String name);
}
HelloSpeaker类:
public class HelloSpeaker implements IHello{
public void hello(String name){
System.out.println("Hello" + name);
}
}
HelloSpeaker相当于一个组件,如果没有源代码,对它的方法前加一些日志功能,可以实现MethodBeforeAdvice接口,例如:
.....
public class LogBeforeAdvice implements MethodBeforeAdvice{
private Logger logger = Logger.getLogger(this.getClass().getName());
public void before(Method method,Object[] args,Object target)) throws Throwable{
logger.log("method starts" + method);
}
}
二、After Advices
After Advices会在目标方法执行之后被调用,可以实现org.springframework.aop.AfterReturningAdvice接口来实现After Advice的逻辑,AfterReturningAdvice接口的定义如下:
public interface AfterReturningAdvice extends Advice{
void afterReturning(Object returnValue,Method m,Object[] args,Object target)
throws Throwable;
}
实现类:
public class LogAfterAdvice implements AfterReturningAdvice{
private Logger logger = Logger.getLogger(this.getClass().getName());
public void afterReturning(............){
logger.log("method ends" + method);
}
}
配置文件中加入After Advice的实例,在ProxyFactoryBean的interceptorNames中增加LogAfterAdvice的引用:
<bean />
<bean id = "logAfterAdvice" class="..." />
<bean id = "helloSpeaker" class="..." />
<bean id = "helloProxy" class="org.springframework.aop.framework.ProxyFactoryBean" >
<property name = "proxyInterfaces" value="...IHello" />
<property name = "target" value = "....HelloSpeaker" /.
<property name = "interceptorNames" >
<list>
<value>logBeforeAdvice</value>
<value>logAfterAdvice</value>
</list>
</bean>
其实可以设计一个类同时实现这两个接口,这里只是演示才将Advice分开。
三、Around Advices
如果在方法执行前后加入Advices的服务,可以直接通过实现org.aopalliance.intercept.MethodInterceptor接口。定义如下:
public interface MethodInterceptor{
public Object invoke(MethodInvocation methodInvocation) throws Throwable;
}
这接口是由AOP Alliance所指定,可以相容于遵守AOP Alliance规范的AOP框架。
与之前不同的是,MethodInterceptor的invoke()方法中,要自行决定是否要执行methodInvocation的proceed()方法来执行目标对象。proceed()返回执行结果,所以可以在invoke()结束之前,有机会修改这个对象并返回其他值。例如:
public class LogInterceptor implements MethodInterceptor{
private Logger logger = Logger.getLogger(this.getClass().getName());
public Object invoke(MethodInvocation methodInvocation) thorws Throwable{
logger.log("method start" + methodInvocation.getMethod());
Object result = null;
try{
result = methodInvocation.proceed();
}
finally{
logger.log("method ends" + methodInvoacation.getMehod());
}
return result;
}
}
配置文件定义与之前相同。只是改名字罢了。
四、Throw Advices
若想在异常发生时通知某些服务对象某些事,可以使用Throws Advice,必须实现org.springframework.aop.ThrowsAdvice接口,然而这个接口并没有定义任何方法,可以自己定义afterThrowing方法,符合一下形式:
afterThrowing([Method],[args],[target],subclassOfThrowable);
异常发生时,Throw Advice只是执行对应的方法,并不能在Throws Advice中将异常处理掉,在Throw Advice执行完毕后,原先的异常仍被传播至应用程序之中,异常处理仍是应用程序本身所要负责的,如果要在Throw Advice处理时中止应用程序的处理流程,做法是丢出其他异常。例如:
public interface IHello{
public void hello(String name) throws Throwable;
}
接着定义类,在hello()方法中模拟异常发生:
public class HelloSpeaker implements IHello{
public void hello(String name) throws Throwable{
System.out.println("Hello" + name);
throw new Exception("发生异常...");
}
}
如果想在应用程序丢出异常时,介入Throw Advice提供一些服务,例如记录一些异常信息,则可以实现ThrowAdvice接口。
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(subclass + "Exception wa thrown in" + method);
}
}
客户程序:
.......
ApplicationContext ac = new ClassPathXmlApplicationContext("conf.xml");
IHello helloProxy = ac.getBean("helloProxy");
try{
helloProxy.hello("Justin");
}
catch(Throwable throwable){
System.err.println(throwable);
}
上面可以看出Throw 并不介入异常的处理,而是增加了日志记录功能,异常处理在应用程序本身中处理。