增强方法也称为通知方法,指标注有@Before、@After、@AfterReturning、@AfterThrowing、@Around注解的Java方法。其中,有前置增强、后置增强、返回增强、异常增强和环绕增强五种增强方式。
一、目录结构
![](https://i-blog.csdnimg.cn/blog_migrate/689cff24c9d673589e2528461844d2aa.png)
二、项目依赖
<!--aop相关依赖 开始-->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.4</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.8.9</version>
</dependency>
<!--aop相关依赖 结束-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.10</version>
<scope>provided</scope>
</dependency>
<!--springboot-web依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
三、代码
自定义注解
package at.xx.annotation;
import java.lang.annotation.*;
/**
* @description:触发aop的自定义注解
*/
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface MyAnnotation {
String value() default "";
}
切面类
package at.xx.aspect;
import at.xx.annotation.MyAnnotation;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
@Component
@Aspect
public class MyAspect {
@Before("@annotation(at.xx.annotation.MyAnnotation)")
public void before(JoinPoint joinPoint) {
//获取方法参数
Object[] args = joinPoint.getArgs();
//获取方法签名(能得到方法的些信息,如:方法名)
Signature signature = joinPoint.getSignature();
//方法名称
String name = signature.getName();
System.out.println(name + "前置增强,方法参数:" + args[0] + args[1]);
}
@After("@annotation(at.xx.annotation.MyAnnotation)")
public void after(JoinPoint joinPoint) {
//获取方法参数
Object[] args = joinPoint.getArgs();
//获取方法签名
Signature signature = joinPoint.getSignature();
String name = signature.getName();
System.out.println(name + "后置增强,方法参数:" + args[0] + args[1]);
}
@AfterReturning(value = "@annotation(at.xx.annotation.MyAnnotation)", returning = "result")
public void afterReturning(JoinPoint joinPoint, Object result) {
System.out.println(name + "返回增强,方法结果:" + result);
}
/**
*
* @param joinPoint
* @param e 通过该参数指定异常,触发该增强
*/
@AfterThrowing(value = "@annotation(at.xx.annotation.MyAnnotation)", throwing = "e")
public void AfterThrowing(JoinPoint joinPoint, NullPointerException e) {
System.out.println("异常增强"+e);
}
@Around("@annotation(at.xx.annotation.MyAnnotation)")
public Object around(ProceedingJoinPoint joinPoint){
//方法返回值
Object result=null;
//获取方法参数
Object[] args = joinPoint.getArgs();
args[0]="张子成";
//获取方法签名
MethodSignature signature = (MethodSignature)joinPoint.getSignature();
//获取注解
MyAnnotation annotation = signature.getMethod().getAnnotation(MyAnnotation.class);
//获取注解参数值
String value = annotation.value();
//todo 原方法执行前增加的业务逻辑
try {
result = joinPoint.proceed(args);
} catch (Throwable throwable) {
throwable.printStackTrace();
}
//todo 原方法执行后增加的业务逻辑
return result;
}
}
controller 层(原有逻辑方法)
package at.xx.controller;
import at.xx.annotation.MyAnnotation;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @author Mr.Z
* @Create 2023-01-29 21:03
* @description:
*/
@RestController
public class AopController {
@MyAnnotation
@GetMapping("/test/before")
public String testAop(String arr1,String arr2){
System.out.println("方法运行");
String s=null;
System.out.println(arr1+arr2);
//s.equals("x");
// int i=1/0;
return "aop";
}
}
四、具体介绍
1、前置增强
前置增强(@Before,又称前置通知):在目标方法执行之前执行。
@Before("@annotation(at.xx.annotation.MyAnnotation)")
public void before(JoinPoint joinPoint) {
//获取方法参数
Object[] args = joinPoint.getArgs();
//获取方法签名
Signature signature = joinPoint.getSignature();
String name = signature.getName();
System.out.println(name + "前置增强,方法参数:" + args[0] + args[1]);
}
2、后置增强
后置增强(@After,又称后置通知):在目标方法执行后执行,无论目标方法运行期间是否出现异常。
注意:后置增强无法获取目标方法执行结果,可以在返回增强中获取。
@After("@annotation(at.xx.annotation.MyAnnotation)")
public void after(JoinPoint joinPoint) {
//获取方法参数
Object[] args = joinPoint.getArgs();
//获取方法签名
Signature signature = joinPoint.getSignature();
String name = signature.getName();
System.out.println(name + "后置增强,方法参数:" + args[0] + args[1]);
}
3、返回增强
返回增强(@AfterReturning,又称返回通知):在目标方法正常结束后执行,可以获取目标方法的执行结果。
@AfterReturning(value = "@annotation(at.xx.annotation.MyAnnotation)", returning = "result")
public void afterReturning(JoinPoint joinPoint, Object result) {
System.out.println(name + "返回增强,方法结果:" + result);
}
4、异常增强
异常增强(@AfterThrowing,又称异常通知):目标方法抛出异常之后执行,可以访问到异常对象,且可以指定在出现哪种异常时才执行增强代码。
/**
*
* @param joinPoint
* @param e 通过该参数指定异常,触发该增强
*/
@AfterThrowing(value = "@annotation(at.xx.annotation.MyAnnotation)", throwing = "e")
public void AfterThrowing(JoinPoint joinPoint, NullPointerException e) {
System.out.println("异常增强"+e);
}
5、环绕增强
环绕增强:目标方法执行前后都可以织入增强处理。
@Around("@annotation(at.xx.annotation.MyAnnotation)")
public Object around(ProceedingJoinPoint joinPoint){
//方法返回值
Object result=null;
//获取方法参数
Object[] args = joinPoint.getArgs();
args[0]="张子成";
//获取方法签名
MethodSignature signature = (MethodSignature)joinPoint.getSignature();
//获取注解
MyAnnotation annotation = signature.getMethod().getAnnotation(MyAnnotation.class);
//获取注解参数值
String value = annotation.value();
//todo 原方法执行前增加的业务逻辑
try {
result = joinPoint.proceed(args);
} catch (Throwable throwable) {
throwable.printStackTrace();
}
//todo 原方法执行后增加的业务逻辑
return result;
}
五、使用场景及注意事项
使用场景:
在不改变原有代码的情况下,增加新的业务逻辑时使用aop(重点掌握@Around);
注意:
1、@Before、@After、@AfterReturning和@AfterThrowing修饰的方法可以通过声明JoinPoint 类型参数变量获取目标方法的信息(方法名、参数列表等信息);@Around修饰的方法必须声明ProceedingJoinPoint类型的参数,该变量可以决定是否执行目标方法;
2、@Before、@After、@AfterReturning和@AfterThrowing修饰的方法没有返回值;而@Around修饰的方法必须有返回值,返回值为目标方法的返回值;