在之前的博客中,我已经给大家讲解了Spring框架中AOP的两种实现方式(Schema-based和AspectJ),并分别简单配置了它们的前后置通知。今天给大家补充其它的两种通知配置方法——异常和环绕通知,首先给大家回顾一下Spring框架中AOP有哪些通知类型:
通知类型 | 接口 | 描述 |
Around(环绕) | org.aopalliance.intercept.MethodInterceptor | 拦截对目标方法调用 |
Before(前置) | org.springframework.aop.MethodBeforeAdvice | 在目标方法执行前调用 |
After(后置) | org.springframework.aop.AfterReturningAdvice | 在目标方法执行后调用 |
Throws(异常) | org.springframework.aop.ThrowsAdvice | 当目标方法抛出异常时调用 |
其中后置通知还分为AfterReturning(返回通知)和AfterThrowing(异常通知)。
AfterReturning(返回通知):仅在目标方法执行成功后执行
AfterThrowing(异常通知):在目标方法抛出异常退出时执行
具体步骤
1.异常通知
所谓异常通知,只有当切点方法出现异常时才能够触发异常通知,否则是无效的。可是在Spring中只有AspectJ提供了异常通知的方法,而在Schema-based中想要配置异常通知,需要按照特定的要求自己去编写一个方法,来实现它。
首先新建一个类去实现throwsAdvice接口,但是它里面没有实现方法。我们需要到官方文档中去找一下
在官方文档中,我们可以看到,提供的方法都实现了ThrowsAdvice这个接口。先写一个异常通知类,类中的方法必须命名为afterThrowing,不然程序会报错。如下:
package a.b.advice;
import java.lang.reflect.Method;
import javax.servlet.ServletException;
import org.springframework.aop.ThrowsAdvice;
public class MyThrow implements ThrowsAdvice{
public void afterThrowing(Exception ex) throws Throwable {
System.out.println("Schema-based方式执行异常通知");
}
// public void afterThrowing(Method m, Object[] args, Object target, ServletException ex) {
// System.out.println("执行异常通知");
// }
}
这个官方文档为我们提供了两种参数方式,规定必须是一个或者四个,详细可以看文档。
在ApplicationContext.xml中配置如下:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<bean id="mythrow" class="a.b.advice.MyThrow"></bean>
<aop:config>
<aop:pointcut expression="execution(* a.b.test.Demo.demo1())" id="mypoint"/>
<aop:advisor advice-ref="mythrow" pointcut-ref="mypoint"/>
<!-- <aop:aspect ref="mythrow">
<aop:pointcut expression="execution(* a.b.test.Demo.demo1())" id="mypoint"/>
<aop:after-throwing method="afterThrowing" throwing="ex" point-ref="mypoint"/>
</aop:aspect> -->
</aop:config>
<bean id="demo" class="a.b.test.Demo"></bean>
<!-- <aop:aspectj-autoproxy proxy-target-class="true"></aop:aspectj-autoproxy> -->
</beans>
Demo类和测试
package a.b.test;
public class Demo {
public void demo1() throws Exception{
int i = 5/0;
System.out.println("demo1");
}
}
package a.b.test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Test {
public static void main(String[] args) {
ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
Demo demo = ac.getBean("demo",Demo.class);
try {
demo.demo1();
} catch (Exception e) {
// TODO Auto-generated catch block
// e.printStackTrace();
}
}
}
在配置异常通知时,我使用了官方文档提供的方法。Demo类不报异常时,能够输出结果。当出现异常时,仍然输出了语句,但是没有结果。我重写类和方法,检查了配置文件。当时没有发现问题,我猜想正常应该是需要回调通知类中的afterThrowing方法。可是这个方法没有回调上,于是在配置文件后又加了一个<aop:aspectj-autoproxy>标签。然而并没有什么卵用,重新翻看官方文档。看了Schema-based和AspectJ中所有的通知配置,AspectJ是用注释实现的通知配置,Schema-based全都是在<aop:aspect>标签当中配置的。于是我又按照官方的要求配置了一遍,还是没什么卵用。我试着把异常类型改了一下,结果奏效。由此得出,官方给的配置示例当中的异常类型,我们自己在编写的时候。不能拿它来使用。代码里面写的是一个算术异常类,我给它接收了一下,放到了MyThrow中。结果可以输出。得出结论异常类型一定要与切点所报的异常类型一致,不然没用。
2.环绕通知
什么是环绕通知。就是把前置通知和后置通知都写到一个通知类中,这就组成了环绕通知。
新建一个类实现MethodInterceptor接口
package a.b.advice;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
public class MyAround implements MethodInterceptor{
@Override
public Object invoke(MethodInvocation arg0) throws Throwable {
System.out.println("环绕-前置");
Object result = arg0.proceed();
System.out.println("环绕-后置");
return result;
}
}
配置ApplicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<bean id="myaround" class="a.b.advice.MyAround"></bean>
<aop:config>
<aop:pointcut expression="execution(* a.b.test.Demo.demo1())" id="mypoint"/>
<aop:advisor advice-ref="myaround" pointcut-ref="mypoint"/>
</aop:config>
<bean id="demo" class="a.b.test.Demo"></bean>
</beans>
输出结果
以上就是使用Schema-based方式来配置异常和环绕通知