案例
- 加入依赖
<!-- spring-aspects会帮我们传递过来aspectjweaver -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>6.0.6</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>6.0.6</version>
</dependency>
- 接口定义
// + - * / 运算的标准接口
public interface Calculator {
int add(int i, int j);
int sub(int i, int j);
int mul(int i, int j);
int div(int i, int j);
}
- 实现纯净实现类,并且加入到 IOC 容器中
import org.springframework.stereotype.Component;
// 实现计算接口,单纯添加 + - * / 实现
@Component
public class CalculatorPureImpl implements Calculator {
@Override
public int add(int i, int j) {
int result = i + j;
return result;
}
@Override
public int sub(int i, int j) {
int result = i - j;
return result;
}
@Override
public int mul(int i, int j) {
int result = i * j;
return result;
}
@Override
public int div(int i, int j) {
int result = i / j;
return result;
}
}
- 现在需要给类的方法中注入日志
LogAdvice,声明切面类
/**
* 日志输出增强类
* 1. 定义方法存储增强代码:具体定义几个方法,根据插入的位置决定!
* 2. 使用注解配置,指定插入目标方法的位置
* 前置 @Before
* 后置 @AfterReturning
* 异常 @AfterThrowing
* 最后 @After
* 环绕 @Around
* 3. 配置切点表达式,选中插入的方法
* 4. 增强也要放到 IOC 容器,也需要标注是一个切面
* 5. @Aspect 声明当前类为一个 AOP 切面,里面包含切点和通知,需要参与 AOP 代理逻辑
*/
@Component
@Aspect
public class LogAdvice {
// 切点 + 增强方法 = 切面
@Before("execution(* com.study.java.service.*.*(..))") // 切点
public void start(){
// 增强方法
System.out.println("方法开始了");
}
@After("execution(* com.study.java.service.*.*(..))")
public void after(){
// 增强方法
System.out.println("方法结束了");
}
@AfterThrowing(pointcut = "execution(* com.study.java.service.*.*(..))", throwing = "ex")
public void error(Exception ex) {
System.out.println("方法报错了:" + ex.getMessage());
}
}
- 开启 Spring 配置类、扫描指定包、开启 Spring AOP 对 AspectJ 注解的支持
@Configuration
@ComponentScan(basePackages = "com.study.java")
// 如果没有这个注解,@Aspect 不会生效
@EnableAspectJAutoProxy
public class MyConfig {}
- 想知道目标函数的具体信息(函数名称、参数值、返回值、异常对象 等等)
@Component
@Aspect
public class LogAdvice {
@Before(value = "execution(public int com.study.java.service.Calculator.add(int,int))")
public void printLogBeforeCore(JoinPoint joinPoint) {
// 1.JoinPoint 包含目标方法的信息
// 方法的签名:一个方法的全部声明信息
Signature signature = joinPoint.getSignature();
// 2.通过方法的签名对象获取目标方法的详细信息
String methodName = signature.getName();
System.out.println("methodName = " + methodName);
int modifiers = signature.getModifiers();
System.out.println("modifiers = " + modifiers);
String declaringTypeName = signature.getDeclaringTypeName();
System.out.println("declaringTypeName = " + declaringTypeName);
// 3.通过JoinPoint对象获取外界调用目标方法时传入的实参列表
Object[] args = joinPoint.getArgs();
// 4.由于数组直接打印看不到具体数据,所以转换为List集合
List<Object> argList = Arrays.asList(args);
System.out.println("[AOP前置通知] " + methodName + "方法开始了,参数列表:" + argList);
}
@AfterReturning(value = "execution(public int com.study.java.service.Calculator.add(int,int))", returning = "targetMethodReturnValue") // 指定用哪个参数接收返回结果
public void printLogAfterCoreSuccess(JoinPoint joinPoint, Object targetMethodReturnValue) {
// 在 targetMethodReturnValue 中接返回结果
String methodName = joinPoint.getSignature().getName();
System.out.println("[AOP返回通知] " + methodName + "方法成功结束了,返回值是:" + targetMethodReturnValue);
}
@AfterThrowing(value = "execution(public int com.study.java.service.Calculator.add(int,int))", throwing = "targetMethodException")
public void printLogAfterCoreException(JoinPoint joinPoint, Throwable targetMethodException) {
String methodName = joinPoint.getSignature().getName();
System.out.println("[AOP异常通知] "+methodName+"方法抛异常了,异常类型是:" + targetMethodException.getClass().getName());
}
}
- 重用切点表达式
上面的案例中多次使用了:execution(public int com.study.java.service.Calculator.add(int,int)),需要抽离出来
@Component
@Aspect
public class LogAdvice {
@Pointcut("execution(public int com.study.java.service.Calculator.add(int,int))")
public void pointCut() {}
@Before(value = "pointCut()")
public void printLogBeforeCore(JoinPoint joinPoint) {
// 1.JoinPoint 包含目标方法的信息
// 方法的签名:一个方法的全部声明信息
Signature signature = joinPoint.getSignature();
// 2.通过方法的签名对象获取目标方法的详细信息
String methodName = signature.getName();
System.out.println("methodName = " + methodName);
int modifiers = signature.getModifiers();
System.out.println("modifiers = " + modifiers);
String declaringTypeName = signature.getDeclaringTypeName();
System.out.println("declaringTypeName = " + declaringTypeName);
// 3.通过JoinPoint对象获取外界调用目标方法时传入的实参列表
Object[] args = joinPoint.getArgs();
// 4.由于数组直接打印看不到具体数据,所以转换为List集合
List<Object> argList = Arrays.asList(args);
System.out.println("[AOP前置通知] " + methodName + "方法开始了,参数列表:" + argList);
}
@AfterReturning(value = "pointCut()", returning = "targetMethodReturnValue") // 指定用哪个参数接收返回结果
public void printLogAfterCoreSuccess(JoinPoint joinPoint, Object targetMethodReturnValue) {
// 在 targetMethodReturnValue 中接返回结果
String methodName = joinPoint.getSignature().getName();
System.out.println("[AOP返回通知] " + methodName + "方法成功结束了,返回值是:" + targetMethodReturnValue);
}
@AfterThrowing(value = "pointCut()", throwing = "targetMethodException")
public void printLogAfterCoreException(JoinPoint joinPoint, Throwable targetMethodException) {
String methodName = joinPoint.getSignature().getName();
System.out.println("[AOP异常通知] "+methodName+"方法抛异常了,异常类型是:" + targetMethodException.getClass().getName());
}
}
或者彻底提取出去,放在一个类中维护
- MyPointCut.java
@Component
public class MyPointCut {
@Pointcut("execution(public int com.study.java.service.Calculator.add(int,int))")
public void pointCut() {}
}
@Component
@Aspect
public class LogAdvice {
@Before(value = "com.study.java.service.MyPointCut.pointCut()")
public void printLogBeforeCore(JoinPoint joinPoint) {
...
}
@AfterReturning(value = "com.study.java.service.MyPointCut.pointCut()", returning = "targetMethodReturnValue") // 指定用哪个参数接收返回结果
public void printLogAfterCoreSuccess(JoinPoint joinPoint, Object targetMethodReturnValue) {
...
}
@AfterThrowing(value = "com.study.java.service.MyPointCut.pointCut()", throwing = "targetMethodException")
public void printLogAfterCoreException(JoinPoint joinPoint, Throwable targetMethodException) {
...
}
}
- 控制某一个 增强优先级 先执行
- @Order(较小的数):优先级高
- @Order(较大的数):优先级低
@Component
@Aspect
@Order(10)
public class TxAdvice {}
@Component
@Aspect
@Order(20)
public class LogAdvice {}