关于AOP的资料:AOP(Spring的面向切面编程)
(1)新增依赖,pom.xml文件中新增:
<!--ASPECT-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
(2) 实现自定义注解:
是一个interface
package com.jojo.cloud.aspect;
import java.lang.annotation.*;
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface JojoTalk {
// 这里定义的属性,是在使用注解时候可以选的,如果不传,就用default后面的属性
int id() default 100;
String name() default "测试注解";
boolean edit() default false;
}
Documented:负责标记和修饰该注解,可以被JavaDoc接口工具文档化
Retention:负责管理该注解的生命周期,通过RetentionPolicy.XXXXX指定。(SOURCE:源码保留,编译后消失。 CLASS:编译时存在,运行时丢失。 RUNTIME:编译,运行,源码都保留,可以被反射发现并调用)
Target:负责该注解的作用范围。也就是该注解可以加在哪里,通过ElementType.XXXX 可以指明。
TYPE:类,接口,枚举上。
METHOD: 方法上。
PARAMETER: 参数上。
LOCAL_VARIABLE:局部变量上。
CONSTRUCTOR:构造方法上。
(3)新增切面方法
@Aspect
@Component
public class JojoTalkMethod {
// 表明以JojoTalk方法作为切入点,同时以talkSome作为增强的代理方法,接下来的几种通知类型全部针对talkSome进行,也等于间接对JojoTalk进行增强
@Pointcut("@annotation(com.jojo.cloud.aspect.JojoTalk)")
public void talkSome(){
}
@Around("talkSome()")
public Object Interceptor(ProceedingJoinPoint joinPoint){
System.out.println("AOP环绕通知开始~~~");
Object retmsg=null;
try {
// 通过proceed()调用目标方法,同时触发Before前置通知,如果在环绕通知中不通过切入点JoinPoint.proceed()调用目标方法,前置通知会失效。
joinPoint.proceed();
} catch (Throwable e) {
e.printStackTrace();
}
System.out.println("环绕通知结束");
Object result = null;
return result;
}
@Before("talkSome()")
public void before(JoinPoint joinPoint) throws Throwable {
MethodSignature sign = (MethodSignature)joinPoint.getSignature();
Method method = sign.getMethod();
JojoTalk jojoTalk = method.getAnnotation(JojoTalk.class);
System.out.println("前置通知:注解里的属性(在AOP增强型方法中可以对其进行逻辑处理)"
+ jojoTalk.id()+jojoTalk.name()+jojoTalk.edit());
}
@After("talkSome()")
public void after() {
System.out.println("后置通知:执行结束,撒花!");
}
}
(4)Controller方法中调用:
@GetMapping("/testAOP")
@JojoTalk()
public void testAOP(){
System.out.println("执行了目标方法!!!!!");
}
这样就使用上了刚刚定义好的@JojoTalk自定义注解,同时也可以使用自定义属性,不传的话就是默认,通过这一步可以做一些业务判断逻辑处理:
(5)测试:
这里可以看得很清楚,环绕通知执行,前置通知执行,目标方法执行,环绕通知收尾,后置通知收尾。
(6)通过传进来的参数做不同的业务逻辑处理/权限校验/判断
只需要在@Before前置通知方法里面加上:
(7)如果这个接口标注在多个Controller里面,发生报错或者记录日志时候,怎么样快速知道是哪个Controller?
两种方法:
(1)定义一个Source参数在自定义注解中,每次使用自定义注解都必须传入该参数。(非常不合理,非常麻烦,而且万一写错了,排查问题都找半天)
(2)通过@Around环绕通知方法中的JoinPoint连接点获取调用者信息: