1. 加入依赖
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
</dependencies>
2. 创建注解类
/**
* @author H
* @date 2022/10/20
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface AopAnnotation {
String value();
int type() default 1;
}
3. 创建切面类
/**
* @author H
* @date 2022/10/20
*/
@Aspect
@Component
public class AopAnnotationAspect {
/**
* 这里的路径填写自定义注解的全路径
*/
@Pointcut("@annotation(com.aop.demo.aop.AopAnnotation)")
public void testAnnotation() {
}
/**
* 在方法执行之前执行
* @param joinPoint
*/
@Before("testAnnotation()")
public void beforeCut(JoinPoint joinPoint) {
MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
Method method = methodSignature.getMethod();
System.out.println("[Before] 注解方式aop开始拦截,当前拦截的方法名:" + method.getName());
}
/**
* 在方法执行之后执行
* @param joinPoint
*/
@After("testAnnotation()")
public void afterCut(JoinPoint joinPoint) {
MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
Method method = methodSignature.getMethod();
System.out.println("[After] 注解方式aop执行的方法:" + method.getName() + "执行完了");
}
/**
* 围绕方法的执行
* @param joinPoint
* @return
* @throws Throwable
*/
@Around("testAnnotation()")
public Object aroundCut(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("[Around] 开始进入环绕通知");
// 获取注解参数
System.out.println("=========获取注解参数开始========");
MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
Method method = methodSignature.getMethod();
AopAnnotation annotation = method.getAnnotation(AopAnnotation.class);
System.out.println(annotation.value());
System.out.println(annotation.type());
System.out.println("=========获取注解参数完成========");
Object proceed = joinPoint.proceed();
System.out.println("[Around] 准备退出环绕");
return proceed;
}
/**
* 在方法返回结果之后执行
* @param joinPoint
* @param result
*/
@AfterReturning(value = "testAnnotation()", returning = "result")
public void afterReturn(JoinPoint joinPoint, Object result) {
MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
Method method = methodSignature.getMethod();
System.out.println("[AfterReturning] 注解方式AOP拦截的方式执行成功,进入返回通知拦截,方法名为:" + method.getName() + ",返回结果为:" + result.toString());
}
/**
* 在方法抛出异常后执行
* @param joinPoint
* @param e
*/
@AfterThrowing(value = "testAnnotation()", throwing = "e")
public void afterThrow(JoinPoint joinPoint, Exception e) {
MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
Method method = methodSignature.getMethod();
System.out.println("[AfterThrowing] 注解方式aop进入方法异常拦截,方法名为:"+ method.getName() + ",异常信息为:" + e.getMessage());
}
}
注意:切面类必须加@Component注解交由spring容器管理,否则切面不生效
3. 创建控制器
/**
* @author H
* @date 2022/10/20
*/
@RestController
public class UserController {
@Autowired
private UserController userController;
@AopAnnotation // 加到控制器上也会生效
@GetMapping("login/{username}")
public String login1(@PathVariable String username) {
String test = userController.test(); // 调用加了aop注解的方法,不能用this调用
return test;
}
@Deprecated
@AopAnnotation(value = "你好,世界", type = 3)
protected String test() {
return "a";
}
}
执行结果:
[Around] 开始进入环绕通知
=========获取注解参数开始========
你好,世界
3
=========获取注解参数完成========
[Before] 注解方式aop开始拦截,当前拦截的方法名:test
[AfterReturning] 注解方式AOP拦截的方式执行成功,进入返回通知拦截,方法名为:test,返回结果为:a
[After] 注解方式aop执行的方法:test执行完了
[Around] 准备退出环绕
注意:
1、@AopAnnotation注解不能加到private修饰的方法上,否则注解不生效;
2、如果A方法调用B方法,在B方法上加了@AopAnnotation注解,不能用this调用,需要注入当前对象,用对象调用,否则不走aop,注解不生效;
3、在controller的web地址映射方法上加@AopAnnotation注解,也是会生效。
4. 多个AOP注解的执行顺序
经过测试,在方法上改变两个注解的顺序不会影响执行顺序。一个方法上多个AOP注解,若要控制执行顺序,可以在切面类上加@Order(1)
注解来控制,数字越小,越先执行。
@AopAnnotation("111")
@AopAnnotation1("222")
@GetMapping("test")
public String test() {
System.out.println("------> 方法执行");
return "success";
}
[Around AopAnnotation] 开始进入环绕通知
[Before AopAnnotation] 注解方式aop开始拦截,当前拦截的方法名:test
[Around AopAnnotation1] 开始进入环绕通知
[Before AopAnnotation1] 注解方式aop开始拦截,当前拦截的方法名:test
------> 方法执行
[AfterReturning AopAnnotation1] 注解方式AOP拦截的方式执行成功,进入返回通知拦截,方法名为:test,返回结果为:success
[After AopAnnotation1] 注解方式aop执行的方法:test执行完了
[Around AopAnnotation1] 准备退出环绕
[AfterReturning AopAnnotation] 注解方式AOP拦截的方式执行成功,进入返回通知拦截,方法名为:test,返回结果为:success
[After AopAnnotation] 注解方式aop执行的方法:test执行完了
[Around AopAnnotation] 准备退出环绕