基于注解的Spring AOP
[1] 导入jar包
com.springsource.net.sf.cglib-2.2.0.jar
com.springsource.org.aopalliance-1.0.0.jar
com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar
commons-logging-1.1.3.jar hamcrest-core-1.3.jar junit-4.12.jar
spring-aop-4.0.0.RELEASE.jar spring-aspects-4.0.0.RELEASE.jar
spring-beans-4.0.0.RELEASE.jar spring-context-4.0.0.RELEASE.jar
spring-core-4.0.0.RELEASE.jar spring-expression-4.0.0.RELEASE.jar
[2]创建被代理类(目标类)
由于我们加入了cglib的支持,所以允许被代理类不实现任何接口。但是这个类必须加入IOC容器,否则Spring没法控制和操作。
@Component
public class Calculator {
public void add(int a, int b) {
System.out.println("(a+b) = " + (a+b));
}
public void sub(int a, int b) {
System.out.println("(a-b) = " + (a-b));
}
public void mul(int a, int b) {
System.out.println("(a×b) = " + (a*b));
}
public void div(int a, int b) {
System.out.println("(a÷b) = " + (a/b));
}
}
[3]创建切面类
@Aspect
@Component
public class LogAspect {
@Before(value="execution(* com.atguigu.spring.aop.target.Calculator.*(..))")
public void doBeforeLog() {
System.out.println("[aop log]method begin");
}
@AfterReturning(value="execution(* com.atguigu.spring.aop.target.Calculator.*(..))")
public void doSuccessLog() {
System.out.println("[aop log]method successfully end");
}
@AfterThrowing(value="execution(* com.atguigu.spring.aop.target.Calculator.*(..))")
public void doExceptionLog() {
System.out.println("[aop log]method ended with exception");
}
@After(value="execution(* com.atguigu.spring.aop.target.Calculator.*(..))")
public void doAfterLog() {
System.out.println("[aop log]method finally end");
}
}
[4]环绕通知
环绕通知对应整个try…catch…finally结构,包括前面四种通知的所有功能。
@Aspect
@Component
public class MessageAspect {
@Around(value = "com.atguigu.spring.aop.aspect.LogAspect.declarPointCut()")
// 环绕通知的通知方法一定要设定有返回值,通常是需要将目标方法执行后的返回值在这里返回
public Object roundAdvice(ProceedingJoinPoint joinPoint) {
// 获取目标方法名
String methodName = joinPoint.getSignature().getName();
// 声明一个变量,用来接收目标方法的返回值
Object targetMethodReturnValue = null;
// 获取外界调用目标方法时传入的实参
Object[] args = joinPoint.getArgs();
try {
// 调用目标方法之前的位置相当于前置通知
System.out.println("[环绕] message before target method " + methodName);
// 调用ProceedingJoinPoint对象的proceed(Object[] var1)调用目标方法
// 将目标方法的返回值赋值给targetMethodReturnValue变量
targetMethodReturnValue = joinPoint.proceed(args);
// 调用目标方法成功返回之后的位置相当于返回通知
System.out.println("[环绕]message after target method " + methodName + " success,return value="+targetMethodReturnValue);
} catch (Throwable throwable) {
throwable.printStackTrace();
// 调用目标方法抛出异常之后的位置相当于异常通知
System.out.println("[环绕]message after target method " + methodName + " failed " + throwable.getClass().getName());
} finally {
// 调用目标方法最终结束之后的位置相当于后置通知
System.out.println("[环绕]message after target method " + methodName + " finally end");
}
return targetMethodReturnValue;
}
}
[5]配置Spring配置文件
<!-- 配置自动扫描的包 -->
<context:component-scan base-package="com.atguigu.spring.aop"/>
<!-- 启用AspectJ注解 -->
<aop:aspectj-autoproxy/>
[6]junit测试
@Test
public void testAOP() {
Calculator calculator = iocContainer.getBean(Calculator.class);
calculator.div(5, 0);
System.out.println("calculator.getClass().getName() = " + calculator.getClass().getName());
}
各个通知获取目标类细节信息
[1]通过JoinPoint接口获取目标方法的方法名、参数
// 使用@Before注解将当前方法定义为前置通知
// value属性:指定切入点表达式,将前置通知“套”在add()方法上
@Before(value = "execution(public void com.atguigu.spring.aop.target.Calculator.div(int,int))")
public void printLogBeforeCoreOperation(JoinPoint joinPoint) {
// 获取方法签名(方法所在类的全类名、方法名等信息)
Signature signature = joinPoint.getSignature();
// 通过方法签名获取方法名
String methodName = signature.getName();
// 外界调用目标方法时传入的参数
Object[] args = joinPoint.getArgs();
System.out.println("[前置]"+ methodName + " method begin" + Arrays.asList(args));
}
[2]方法返回值
在返回通知中,通过@AfterReturning注解的returning属性获取目标方法的返回值
// 使用@AfterReturning注解将当前方法定义为返回通知
@AfterReturning(
pointcut = "execution(public int com.atguigu.spring.aop.target.Calculator.div(int,int))",
// 使用returning属性指定一个名称,Spring会自动将目标方法的返回值传入到同名的参数位置
// 注意:目标方法必须确定有返回值,如果目标方法返回值是void,那么Spring给参数位置传入null
returning = "targetMethodReturnValue"
)
public void printLogAfterCoreOperationSuccess(Object targetMethodReturnValue){
System.out.println("[返回]method success,return value=" + targetMethodReturnValue);
}
[3]目标方法抛出的异常
在异常通知中,通过@AfterThrowing注解的throwing属性获取目标方法抛出的异常对象
// 使用@AfterThrowing注解将当前方法定义为异常通知
@AfterThrowing(
value = "execution(public int com.atguigu.spring.aop.target.Calculator.div(int,int))",
throwing = "exception"
)
public void printLogAfterCoreOperationFailed(Throwable exception) {
System.out.println("[异常]method failed,exception name=" + exception.getClass().getName());
}