AspectJ支持5种类型的通知注解:
@Before:前置通知,在方法执行之前执行;@After:后置通知,在方法执行之后执行;@AfterRunning:返回通知,在方法返回结果之后执行(因此该通知方法在方法抛出异常时,不能执行);@AfterThrowing:异常通知,在方法抛出异常之后执行;@Around:环绕通知,围绕着方法执行。示例项目新建:
第一步:新建spring aop项目
第二步:添加spring-aop.xml Spring配置文件:
<?xml version="1.0" encoding="UTF-8"?><beans xmlns="/schema/beans"xmlns:xsi="/2001/XMLSchema-instance" xmlns:aop="/schema/aop"xmlns:context="/schema/context"xsi:schemaLocation="/schema/beans /schema/beans/spring-beans.xsd/schema/context /schema/context/spring-context-4.3.xsd/schema/aop /schema/aop/spring-aop-4.3.xsd"><!-- 配置自动扫描的包 --><context:component-scan base-package="com.dx.spring.beans.aop"></context:component-scan><!-- 配置是AspectJ注解起作用 :自动为匹配的类生成代理对象 --><aop:aspectj-autoproxy></aop:aspectj-autoproxy></beans>
View Code
第三步:添加接口类IArithmeticCalculator.java,ArithmeticCalculatorImpl.java Spring组件
package com.dx.spring.beans.aop;/*** Description:Addition, subtraction, multiplication, and division*/public interface IArithmeticCalculator {int add(int i, int j);int sub(int i, int j);int multi(int i, int j);int div(int i, int j);}
View Code
package com.dx.spring.beans.aop;import org.ponent;@Component("arithmeticCalculator")public class ArithmeticCalculatorImpl implements IArithmeticCalculator {@Overridepublic int add(int i, int j) {int result = i + j;return result;}@Overridepublic int sub(int i, int j) {int result = i - j;return result;}@Overridepublic int multi(int i, int j) {int result = i * j;return result;}@Overridepublic int div(int i, int j) {int result = i / j;return result;}}
View Code
第四步:添加LoggingAspect.java切面
package com.dx.spring.beans.aop;import java.util.List;import java.util.Arrays;import org.aspectj.lang.JoinPoint;import org.aspectj.lang.annotation.After;import org.aspectj.lang.annotation.Aspect;import org.aspectj.lang.annotation.Before;import org.ponent;//把这个类声明为一个切面:需要把该类放入到IOC容器中、再声明为一个切面。@Aspect@Componentpublic class LoggingAspect {// 在这里注册通知方法。}
第五步:添加测试类Client.java
package com.dx.spring.beans.aop;import org.springframework.context.ApplicationContext;import org.springframework.context.support.ClassPathXmlApplicationContext;public class Client {public static void main(String[] args) {// 1:创建Spring的IOC容器;ApplicationContext ctx = new ClassPathXmlApplicationContext("spring-aop.xml");// 2.从IOC容器中获取Bean的实例IArithmeticCalculator arithmeticCalculator = (IArithmeticCalculator) ctx.getBean("arithmeticCalculator");// 3.使用Bean}}
@Before:前置通知
在切面类LoggingAspect中添加前置通知:
// 声明该方法为一个前置通知:在目标方法开始之前执行@Before("execution(public int com.dx.spring.beans.aop.IArithmeticCalculator.*(int, int))")public void beforeMethod(JoinPoint joinpoint) {String methodName = joinpoint.getSignature().getName();List<Object> args = Arrays.asList(joinpoint.getArgs());System.out.println("before method " + methodName + " with " + args);}
Client.java添加测试代码&执行测试:
int result = arithmeticCalculator.add(1, 3);System.out.println(result);result = arithmeticCalculator.div(4, 1);System.out.println(result);
before method add with [1, 3]
before method div with [4, 0]
@After:后置通知
在切面类LoggingAspect中添加后置通知方法:
// 声明该方法为一个后置通知:在目标方法结束之后执行(无论方法是否抛出异常)。// 但是因为当方法抛出异常时,不能返回值为null,因此这里无法获取到异常值。@After(value = "execution(public int com.dx.spring.beans.aop.IArithmeticCalculator.*(int, int))")public void afterMethod(JoinPoint joinpoint) {String methodName = joinpoint.getSignature().getName();List<Object> args = Arrays.asList(joinpoint.getArgs());System.out.println("after method " + methodName);}
Client.java添加测试代码&执行测试:
int result = arithmeticCalculator.add(1, 3);System.out.println(result);result = arithmeticCalculator.div(4, 0);System.out.println(result);
执行结果:
备注:从执行结果中我们可以看出,即使方法抛出异常,后置通知方法也会执行。
@AfterRunning:返回通知
修改切面类LoggingAspect,添加返回通知方法:
/*** 声明该方法为一个返回通知:在目标方法返回结果时后执行(当方法抛出异常时,无法执行)。* 但是因为当方法抛出异常时,类似代码* {@code* try <br/>* {<br/>* // before 前置通知 <br/>* // do action method <br/>* // after returning 返回通知,可以访问到方法的返回值<br/>* }* catch(Exception e){* e.printStackTrace();* // after throwing 异常通知,可以访问到方法出现的异常* }* // after 后置通知,因为方法可以抛出异常,所以访问不到方法的返回值* }* */@AfterReturning(value = "execution(public int com.dx.spring.beans.aop.IArithmeticCalculator.*(int, int))", returning = "result")public void afterReturningMethod(JoinPoint joinpoint, Object result) {String methodName = joinpoint.getSignature().getName();List<Object> args = Arrays.asList(joinpoint.getArgs());System.out.println("after method " + methodName + " with returning " + (result == null ? "NULL" : result.toString()));}
注意:返回通知注解中,参数是多一个了returning参数,该参数定义通知方法接收返回值的别名。
在测试类Client.java中追加测试代码:
int result = arithmeticCalculator.add(1, 3);System.out.println(result);result = arithmeticCalculator.div(4, 0);System.out.println(result);
@AfterThrowing:异常通知
修改切面类LoggingAspect,添加异常通知方法:
/*** 定义一个异常通知函数:* 只有在方法抛出异常时,该方法才会执行,而且可以接受异常对象。* */@AfterThrowing(value = "execution(public int com.dx.spring.beans.aop.IArithmeticCalculator.*(int, int))", throwing = "ex")public void afterThrowingMethod(JoinPoint joinpoint, Exception ex) {String methodName = joinpoint.getSignature().getName();List<Object> args = Arrays.asList(joinpoint.getArgs());System.out.println("after method " + methodName + " occurs exception: " + (ex == null ? "NULL" : ex.getMessage()));}
备注:只有在方法抛出异常时,异常通知方法才会执行,而且可以接受异常对象。
在测试类Client.java中追加测试代码:
int result = arithmeticCalculator.add(1, 3);System.out.println(result);result = arithmeticCalculator.div(4, 0);System.out.println(result);
打印信息
@Around:环绕通知
环绕通知其他方式不同,它相当于代理对象使用时效果一样。可以在方法前、后、返回、异常打印信息。
我们先看代理方法打印信息时如何处理,之后再看环绕通知如何处理。
代理方法实现通知:
package com.dx.spring.beans.aop;import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;public class ArithmeticCalculatorProxy implements InvocationHandler {private Object obj;public ArithmeticCalculatorProxy(Object obj) {this.obj = obj;}public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {Object object = null;try {// *** 前置通知,在方法执行之前执行System.out.println("before " + method);// 真实的调用方法操作object = method.invoke(obj, args);// *** 返回通知,在方法返回结果之后执行(因此该通知方法在方法抛出异常时,不能执行);System.out.println("before returning " + method);} catch (Exception ex) {ex.printStackTrace();// *** 异常通知,在方法抛出异常之后执行;System.out.println("before throwing " + method);throw ex;}// *** 后置通知,在方法执行之后执行;因为方法可以抛出异常,所以访问不到方法的返回值System.out.println("after " + method);return object;}}
环绕通知:
修改切面类LoggingAspect,添加环绕通知:
package com.dx.spring.beans.aop;import java.util.List;import java.util.Arrays;import org.aspectj.lang.JoinPoint;import org.aspectj.lang.ProceedingJoinPoint;import org.aspectj.lang.annotation.After;import org.aspectj.lang.annotation.AfterReturning;import org.aspectj.lang.annotation.AfterThrowing;import org.aspectj.lang.annotation.Around;import org.aspectj.lang.annotation.Aspect;import org.aspectj.lang.annotation.Before;import org.ponent;//把这个类声明为一个切面:需要把该类放入到IOC容器中、再声明为一个切面。@Aspect@Componentpublic class LoggingAspect {// // 声明该方法为一个前置通知:在目标方法开始之前执行// @Before("execution(public int com.dx.spring.beans.aop.IArithmeticCalculator.*(int, int))")// public void beforeMethod(JoinPoint joinpoint) {// String methodName = joinpoint.getSignature().getName();// List<Object> args = Arrays.asList(joinpoint.getArgs());// System.out.println("before method " + methodName + " with " + args);// }//// // 声明该方法为一个后置通知:在目标方法结束之后执行(无论方法是否抛出异常)。// // 但是因为当方法抛出异常时,不能返回值为null,因此这里无法获取到异常值。// @After(value = "execution(public intcom.dx.spring.beans.aop.IArithmeticCalculator.*(int,int))")// public void afterMethod(JoinPoint joinpoint) {// String methodName = joinpoint.getSignature().getName();// List<Object> args = Arrays.asList(joinpoint.getArgs());// System.out.println("after method " + methodName);// }//// /**//* 声明该方法为一个返回通知:在目标方法返回结果时后执行(当方法抛出异常时,无法执行)。 但是因为当方法抛出异常时,类似代码 {@code//* try <br/>//* { <br/>//* // before 前置通知 <br/>//* // do action method <br/>//* // after returning 返回通知,可以访问到方法的返回值 <br/>//* } catch(Exception e){ e.printStackTrace(); // after throwing//* 异常通知,可以访问到方法出现的异常 } // after 后置通知,因为方法可以抛出异常,所以访问不到方法的返回值 }//*/// @AfterReturning(value = "execution(public intcom.dx.spring.beans.aop.IArithmeticCalculator.*(int,int))", returning = "result")// public void afterReturningMethod(JoinPoint joinpoint, Object result) {// String methodName = joinpoint.getSignature().getName();// List<Object> args = Arrays.asList(joinpoint.getArgs());// System.out.println(//"after method " + methodName + " with returning " + (result == null ? "NULL" : result.toString()));// }//// /**//* 定义一个异常通知函数: 只有在方法跑吹异常时,该方法才会执行,而且可以接受异常对象。//*/// @AfterThrowing(value = "execution(public intcom.dx.spring.beans.aop.IArithmeticCalculator.*(int,int))", throwing = "ex")// public void afterThrowingMethod(JoinPoint joinpoint, Exception ex) {// String methodName = joinpoint.getSignature().getName();// List<Object> args = Arrays.asList(joinpoint.getArgs());// System.out.println(//"after method " + methodName + " occurs exception: " + (ex == null ? "NULL" : ex.getMessage()));// }@Around(value = "execution(public int com.dx.spring.beans.aop.IArithmeticCalculator.*(int, int))")public Object aroundMethod(ProceedingJoinPoint pJoinPoint) throws Exception {String methodName = pJoinPoint.getSignature().getName();List<Object> args = Arrays.asList(pJoinPoint.getArgs());Object result = null;try {// 前置通知System.out.println("before method " + methodName + " with " + args);// 执行目标方法result = pJoinPoint.proceed();// 返回通知System.out.println("after method " + methodName + " returning " + result);} catch (Throwable ex) {// 异常通知System.out.println("after method " + methodName + " occurs exception: " + ex.getMessage());throw new Exception(ex);}// 后置通知System.out.println("after method " + methodName);return result;}}
修改Client.java测试类,添加代码:
int result = arithmeticCalculator.add(1, 3);System.out.println(result);result = arithmeticCalculator.div(4, 0);System.out.println(result);
执行结果