现象:
spring-aop基础使用测试记录
org.springframework.boot
spring-boot-starter-aop
方法:
定义RequestController 做为拦截对象
定义MyTestAop做aop测试
定义自定义注解MyAnnitation 拥有两个属性 message和order
1:定义controller test/a方法 返回A
2:aop定义execution表达式
代码:
/**
* 定义切入点 : execution表达式
* 通过指定包路径和方法 可匹配到方法级别
* ..* : 这个包下全部类
* .*(..) : 这个类下面全部方法
* 可 && || ! 使用
*/
@Pointcut("execution(public * com.spring.aop.api..*.*(..))")
public void pointE(){}
/**
* 前置通知:在我们执行目标方法之前运行
* 使用execution表达式
*/
@Before(value = "pointE()")
public void requestBefore(JoinPoint joinPoint){
var args = joinPoint.getArgs();
var first = Arrays.stream(args).findFirst().orElse("");
var json = String.valueOf(first);
log.debug("=================前置通知执行中:{}",json);
}
1:定义需要拦截的controller方法 test/b
@PostMapping("/b")
public String getB(@RequestBody AopTestRequest request){
log.debug("b请求执行:{}",request);
return "B";
}
2:aop定义within表达式
/**
* 定义切入点 : within表达式
* 通过指定类路径 只能匹配类、包等级别不能详细控制方法
* 指定拦截RequestController类
*/
@Pointcut("within(com.spring.aop.api.RequestController)")
public void pointW(){}
3:使用后置通知测试
/**
* 在我们执行目标方法结束之后,不管有没有异常
* 后置通知测试within表达式
*/
@After(value = "pointW()")
public void requestAfter(JoinPoint joinPoint){
var args = joinPoint.getArgs();
var first = Arrays.stream(args).findFirst().orElse("");
var json = String.valueOf(first);
log.debug("=================后置通知执行中:{}",json);
}
1:定义需要拦截的test/c方法
@PostMapping("/c")
public String getC(@RequestBody AopTestRequest request){
log.debug("c请求执行:{}",request);
return "C";
}
2:定义target表达式
/**
* 定义切入点 : target表达式
* 目标对象为指定的类型被拦截
* 此处拦截RequestController类型的对象
*/
@Pointcut("target(com.spring.aop.api.RequestController)")
public void pointT(){}
3:使用返回通知测试
/**
* 在我们的目标方法正常返回后运行
* 返回通知测试target表达式
*/
@AfterReturning(value ="pointT()" ,returning = "result")
public void requestAfterReturning(JoinPoint joinPoint, Object result){
var args = joinPoint.getArgs();
var first = Arrays.stream(args).findFirst().orElse("");
var json = String.valueOf(first);
log.debug("=================返回通知执行中:{}",json);
log.debug("=================返回通知执行中返回:{}",result);
}
1:定义test/d方法
@PostMapping("/d")
public String getD(@RequestBody AopTestRequest request){
log.debug("d请求执行:{}",request);
var i = 4 / 0;
return "D";
}
2:定义aop args表达式
/**
* 定义切入点 : args 表达式
* 匹配方法中的参数
* args(com.spring.aop.api.request.AopTestRequest) 匹配只有一个参数且指定类型
* args(com.spring.aop.api.request.AopTestRequest,..) 匹配多个参数第一个指定类型
* args(com.spring.aop.api.request.AopTestRequest,com.spring.aop.api.request.AopTestRequest2) 匹配多个参数指定多个类型
* within 指定包路径只匹配自己的 防止匹配到其他包里面的final对象 导致无法代理报错
*/
@Pointcut("args(com.spring.aop.api.request.AopTestRequest) && within(com.spring.aop..*)")
public void pointA(){}
3:定义异常通知测试
/**
* 异常通知:在我们的目标方法出现异常后运行
*/
@AfterThrowing(value = "pointA()",throwing = "e")
public void requestAfterThrowing(JoinPoint joinPoint,Exception e){
var args = joinPoint.getArgs();
var first = Arrays.stream(args).findFirst().orElse("");
var json = String.valueOf(first);
log.debug("=================异常通知执行中:{}",json);
log.debug("=================异常通知执行中e:{}",e.getMessage());
}
1:定义方法test/e
@PostMapping("/e")
public String getE(@RequestBody AopTestRequest request){
log.debug("e请求执行:{}",request);
return "e";
}
2:aop定义@target表达式
/**
* 定义切入点 : @target表达式
* 匹配的目标的类有一个指定的注解
* 这个类全部方法都拦截
* 此处拦截有自定义注解MyAnnitation的类
*/
@Pointcut("@target(com.spring.aop.annotation.MyAnnitation) && within(com.spring.aop..*)")
public void pointTA(){}
3:在controller 上使用自定义注解MyAnnitation
4:定义环绕通知测试
/**
* 动态代理,需要手动执行jionPoint.process(),其实就是执行我们的目标方法执行之前,相当于前置通知,执行之后就相当于我们的后置通知
*/
@Around("pointTA()")
public void requestAround(ProceedingJoinPoint point){
var methodName = point.getSignature().getName();
try{
// 先执行前置通知
log.debug("=================环绕通知-前置通知:执行中:{}",methodName);
// 执行目标方法
var result = point.proceed();
// 正常返回通知
log.debug("=================环绕通知-正常返回通知:执行中:{}",result);
}catch (Throwable e){
log.debug("=================环绕通知-异常通知执行中:",e);
}
// 后置通知
log.debug("=================环绕通知-后置通知:执行中:{}",methodName);
}
1:定义方法test/f
@PostMapping("/f")
public String getF(@RequestBody AopTestRequest2 request){
log.debug("f请求执行:{}",request);
return "f";
}
2:定义aop @within表达式
/**
* 定义切入点 : @within表达式
* 判断被调用的方法所属的类中是否声明了指定注解
* 此处被调用方法所属的类是RequestController
*/
@Pointcut("@within(com.spring.aop.annotation.MyAnnitation) && within(com.spring.aop..*)")
public void pointWI(){}
3:定义前置通知测试
/**
* 前置通知:在我们执行目标方法之前运行
* 测试@within表达式
*/
@Before(value = "pointWI()")
public void requestBefore(JoinPoint joinPoint){
var args = joinPoint.getArgs();
var first = Arrays.stream(args).findFirst().orElse("");
var json = String.valueOf(first);
log.debug("=================前置通知执行中:{}",json);
}
4:被调用方法所属类 RequestController增加自定义注解
5:访问test/f方法测试
1:定义test/g方法 使用AopTestRequest2 入参
@PostMapping("/g")
public String getG(@RequestBody AopTestRequest2 request){
log.debug("g请求执行:{}",request);
return "g";
}
2:定义aop表达式
/**
* 定义切入点 : @args表达式
* 方法参数上有指定的注解,被匹配
* within指定只匹配自己的路径 防止匹配到其他final的对象
*/
@Pointcut("@args(com.spring.aop.annotation.MyAnnitation) && within(com.spring.aop..*)")
public void pointAR(){}
3: 使用前置通知测试
/**
* 前置通知:在我们执行目标方法之前运行
*/
@Before(value = "pointAR()")
public void requestBefore(JoinPoint joinPoint){
var args = joinPoint.getArgs();
var first = Arrays.stream(args).findFirst().orElse("");
var json = String.valueOf(first);
var simpleName = joinPoint.getSignature().getDeclaringType().getSimpleName();
log.debug("=================前置通知执行中:类名:{}",simpleName);
log.debug("=================前置通知执行中:{}",json);
}
4:访问的方法入参对象增加自定义注解
5:test/g方法参数的类使自定义注解@MyAnnitation
5:方法test/g方法测试
1:定义方法test/h
方法上携带自定义注解@MyAnnitation
@PostMapping("/h")
@MyAnnitation(message = "消息",order = 100)
public String getH(@RequestBody AopTestRequest request){
log.debug("h请求执行:{}",request);
return "H";
}
2: aop定义前置通知测试@annotation
/**
* 前置通知:自定义注解
*/
@Before(value = "@annotation(myAnnitation)")
public void requestBefore(JoinPoint joinPoint,MyAnnitation myAnnitation){
var args = joinPoint.getArgs();
var first = Arrays.stream(args).findFirst().orElse("");
var json = String.valueOf(first);
log.debug("=================前置通知执行中:{}",json);
// 1,获取自定义注解中的数据内容
var message = myAnnitation.message();
var order = myAnnitation.order();
log.debug("=================前置通知执行获取自定义注解的内容-message:{}、order:{}",message,order);
}