介绍spring AOP前置通知、后置通知、返回通知、异常通知、环绕通知
依赖:
1.aspectjrt
2.aspectjweaver
详细:
pom.xml 增加配置:
<dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>3.8.1</version> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>4.2.6.RELEASE</version> </dependency> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjrt</artifactId> <version>1.8.9</version> </dependency> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.8.9</version> <scope>runtime</scope> </dependency> </dependencies>
ArithmeticCalculator.java
package com.shuoeasy.test; /** * 定义计算器接口 * */ public interface ArithmeticCalculator { double add(double num1, double num2); double sub(double num1, double num2); double mul(double num1, double num2); double div(int num1, int num2); }
ArithmeticCalculatorImpl.java:
package com.shuoeasy.test;
import org.springframework.stereotype.Component;
/**
* 业务类
*/
@Component("arithmeticCalculator")
public class ArithmeticCalculatorImpl implements ArithmeticCalculator{
public double add(double num1, double num2) {
double result = num1 + num2;
return result;
}
public double sub(double num1, double num2) {
double result = num1 - num2;
return result;
}
public double mul(double num1, double num2) {
double result = num1 * num2;
return result;
}
public double div(int num1, int num2) {
double result = num1 / num2;
return result;
}
}LogAspect.java
package com.shuoeasy.test;
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.springframework.stereotype.Component;
// 声明为一个切面:需要把该类放入IOC容器中、再声明为一个切面
@Aspect
@Component
public class LogAspect {
public static final String EDP = "execution(public double com.shuoeasy.test.ArithmeticCalculator.add(double, double))";
// 前置通知。声明该方法是一个前置通知:在目标方法之前执行
@Before(EDP)
public void beforeMethod(JoinPoint joinPoint){
String methodName = joinPoint.getSignature().getName();
Object[] args = joinPoint.getArgs();
System.out.println("The method " + methodName + " @Before, args:" + Arrays.asList(args));
}
// 后置通知。目标方法执行之后执行,无论该方法是否出现异常
@After("execution(* com.shuoeasy.test.*.*(..))")
public void afterMethod(JoinPoint joinPoint){
String methodName = joinPoint.getSignature().getName();
Object[] args = joinPoint.getArgs();
System.out.println("The method " + methodName + " @After, args:" + Arrays.asList(args));
}
// 返回通知。在方法正常执行后,返回通知是可以访问该方法返回值的
@AfterReturning(value="execution(* com.shuoeasy.test.*.*(..))",returning="result")
public void afterReturning(JoinPoint joinPoint, Object result){
String methodName = joinPoint.getSignature().getName();
Object[] args = joinPoint.getArgs();
System.out.println("The method " + methodName + " @AfterReturning, return:" + result);
}
// 异常通知。在目标方法出现异常时执行代码,可以访问到异常对象,且可以指定出现特定异常时执行通知代码
@AfterThrowing(value="execution(* com.shuoeasy.test.*.*(..))",throwing="ex")
public void afterThrowing(JoinPoint joinPoint, Exception ex){
// 也可以将Exception改为特定的异常类型NullPointerException ex
String methodName = joinPoint.getSignature().getName();
System.out.println("The method " + methodName + " @AfterThrowing, ex:" + ex.toString());
}
// 环绕通知。需要携带ProceedingJoinPoint类型的参数。
// 类似动态代理的全过程ProceedingJoinPoint类型的参数可以决定是否执行目标方法。
// 且环绕通知有返回值,返回值即目标方法的返回值
@Around("execution(* com.shuoeasy.test.*.*(..))")
public Object aroundMethod(ProceedingJoinPoint pjd){
//return 100.0; // 如果return 100.0,目标方法的返回值就被强制改为100.0
Object result = null;
String methodName = pjd.getSignature().getName();
Object[] args = pjd.getArgs();
try {
// 前置通知
System.out.println("The method " + methodName + " @Around->Before, args:" + Arrays.asList(args));
// 执行目标方法
result = pjd.proceed();
// 后置通知
System.out.println("The method " + methodName + " @Around->AfterReturning, return:" + result);
} catch (Throwable e) {
// 异常通知
System.out.println("The method " + methodName + " @Around->AfterThrowing, e:" + e.toString());
throw new RuntimeException(e);
}
// 后置通知
System.out.println("The method " + methodName + " @After, args:" + Arrays.asList(args));
return result;
}
}bean.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:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context" 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/context http://www.springframework.org/schema/context/spring-context-4.2.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.2.xsd"> <!-- 自动扫描的包 --> <context:component-scan base-package="com.shuoeasy.test"></context:component-scan> <!-- 使用Aspjectj 注解起作用:自动为匹配的类生成代理对象 --> <aop:aspectj-autoproxy></aop:aspectj-autoproxy> </beans>
Main.java
package com.shuoeasy.test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Main {
public static void main(String[] args) {
// 1.创建spring的IOC容器
ApplicationContext ctx = new ClassPathXmlApplicationContext("bean.xml");
// 2.从IOC容器中获取bean的实例
ArithmeticCalculator arithmeticCalulator = (ArithmeticCalculator)ctx.getBean("arithmeticCalculator");
// 3.使用bean
double result = arithmeticCalulator.add(2, 3);
System.out.println("result=" + result);
}
}输出:
The method add @Around->Before, args:[2.0, 3.0]
The method add @Before, args:[2.0, 3.0]
The method add @Around->AfterReturning, return:5.0
The method add @After, args:[2.0, 3.0]
The method add @After, args:[2.0, 3.0]
The method add @AfterReturning, return:5.0
result=5.0