Spring与AOP之AspectJ基于XML的实现
AspectJ 除了提供了基于注解的 AOP 的实现外,还提供了以 XML 方式的实现。切面就是一个 POJO 类,而用于增强的方法就是普通的方法。通过配置文件,将切面中的功能增强织入到了目标类的目标方法中。
实现步骤
(1) 定义业务接口与实现类
//主业务接口
public interface ISomeService {
//主业务方法
void doFirst();
//主业务方法
String doSecond();
//主业务方法
void doThird();
}
//目标类
public class SomeServiceImpl implements ISomeService {
//目标方法
@Override
public void doFirst() {
System.out.println("执行doFirst()方法");
}
//目标方法
@Override
public String doSecond() {
System.out.println("执行doSecond()方法");
return "abcde";
}
//目标方法
@Override
public void doThird() {
System.out.println("执行doThird()方法" + 3 / 0);
System.out.println("执行doThird()方法");
}
}
(2) 定义切面 POJO 类
该类为一个 POJO 类,将作为切面出现。其中定义了若干普通方法,将作为不同的通知方法。
// 表示当前类为切面
public class MyAspectJ {
//前置通知
public void myBefore() {
System.out.println("执行前置通知方法");
}
// @Before("execution(* *..ISomeService.doFirst(..))")
public void myBefore(JoinPoint jp) {
System.out.println("执行前置通知方法 jp = " + jp);
}
//后置通知
public void myAfterReturning() {
System.out.println("执行后置通知方法");
}
public void myAfterReturning(Object result) {
System.out.println("执行后置通知方法 result = " + result);
}
//环绕通知
public Object myAround(ProceedingJoinPoint pjp) throws Throwable{
System.out.println("执行环绕通知方法,目标方法执行之前");
//执行目标方法
Object result = pjp.proceed();
System.out.println("执行环绕通知方法,目标方法执行之后");
if (result != null) {
result = ((String)result).toUpperCase();
}
return result;
}
//异常通知
public void myAfetrThrowing() {
System.out.println("执行异常通知方法");
}
//使用切入点,叫 doThirdPointcut()
public void myAfterThrowing(Exception ex) {
System.out.println("执行异常通知方法 ex = " + ex.getMessage());
}
//最终通知
public void myAfter() {
System.out.println("执行最终通知方法");
}
}
(3) 注册目标对象与 POJO 切面类
<!-- 注册切面 -->
<bean id="myAspectJ" class="com.huang.xml.MyAspectJ"/>
<!-- 注册目标对象 -->
<bean id="someService" class="com.huang.xml.SomeServiceImpl"/>
(4) 在容器中定义 AOP 配置
<!-- AOP配置 -->
<aop:config>
<aop:aspect ref="myAspectJ">
<aop:pointcut expression="execution(* *..ISomeService.doFirst(..))" id="doFirstPointcut"/>
<aop:pointcut expression="execution(* *..ISomeService.doSecond(..))" id="doSecondPointcut"/>
<aop:pointcut expression="execution(* *..ISomeService.doThird(..))" id="doThirdPointcut"/>
</aop:aspect>
</aop:config>
通过其子标签<aop:pointcut/>定义切入点,该标签有两个属性, id 与 expression。分别用于指定该切入点的名称及切入点的值。 expression 的值为 execution 表达式。
子标签<aop:aspect/>定义具体的织入规则:根据不同的通知类型,确定不同的织入时间;将 method 指定的增强方法,按照指定织入时间,织入到切入点指定的目标方法中。
<aop:aspect/>的 ref 属性用于指定使用哪个切面。<aop:aspect/>的子标签是各种不同的通知类型。不同的通知所包含的属性是不同的,但也有共同的属性。
- method:指定该通知使用的切面中的增强方法。
- pointcut-ref:指定该通知要应用的切入点。
AspectJ 的 6 种通知的 XML 标签如下:
- <aop:before/>:前置通知
- lt;aop:after-returning/>: 后置通知
- <aop:around/>:环绕通知
- <aop:after-throwing/>:异常通知
- <aop:after/>:最终通知
- <aop:declare-parents/>:引入通知
(5) 定义测试类
@Test
public void test01() {
String resource = "com/huang/xml/applicationContext.xml";
ApplicationContext ac = new ClassPathXmlApplicationContext(resource);
//serviceProxy为代理对象,而非目标对象
ISomeService service = (ISomeService) ac.getBean("someService");
service.doFirst();
System.out.println("----------------------");
service.doSecond();
System.out.println("----------------------");
service.doThird();
}
<aop:before/>前置通知
<!-- 前置通知 -->
<aop:before method="myBefore" pointcut-ref="doFirstPointcut"/>
<aop:before method="myBefore(org.aspectj.lang.JoinPoint)" pointcut-ref="doFirstPointcut"/>
运行结果
<aop:after-returning/>后置通知
其 XML 的配置中,有一个属性 returning,指定用于接收目标方法的返回值所使用的变量名。其可作为增强方法的参数出现。
<!-- 后置通知 -->
<aop:after-returning method="myAfterReturning" pointcut-ref="doSecondPointcut"/>
<aop:after-returning method="myAfterReturning(java.lang.Object)" pointcut-ref="doSecondPointcut" returning="result"/>
运行结果
<aop:around/>环绕通知
环绕通知的增强方法一般返回类型为 Object,是目标方法的返回值。并且可以包含一个参数 ProceedingJoinPoint,其方法 proceed()可执行目标方法。
<!-- 环绕通知 -->
<aop:around method="myAround" pointcut-ref="doSecondPointcut"/>
运行结果
<aop:after-throwing/>异常通知
其 XML 的配置中,有一个属性 throwing,指定用于接收目标方法所抛出异常的变量名。其可作为增强方法的参数出现,该参数为 Throwable 类型。
<!-- 异常通知 -->
<aop:after-throwing method="myAfterThrowing(java.lang.Exception)" pointcut-ref="doThirdPointcut" throwing="ex"/>
运行结果
<aop:after/>最终通知
<!-- 最终通知 -->
<aop:after method="myAfter" pointcut-ref="doThirdPointcut"/>
运行结果
推荐阅读
-
Spring Aop之AspectJ注解配置实现日志管理的方法
-
Android开发之图形图像与动画(三)Animation效果的XML实现
-
基于Android XML解析与保存的实现
-
Spring实战之XML与JavaConfig的混合配置详解
-
Spring Aop之AspectJ注解配置实现日志管理的方法
-
Android开发之图形图像与动画(三)Animation效果的XML实现
-
基于Android XML解析与保存的实现
-
Spring实战之XML与JavaConfig的混合配置详解
-
jsp基于XML实现用户登录与注册的实例解析(附源码)
-
Android埋点方案的简单实现-AOP之AspectJ