AOP技术:
关注点:就是重复代码,也就是相同点。
切面:关注点形成的类,可以叫做切面类,将重复的代码抽取出来,在运行的时候业务方法上动态植入。
切点:执行的目标对象,也就是对应的方法
1、首先添加pom引用
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
2、aop五种通知类型示例代码
package com.example.demo.web;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
//表示切入点
@Aspect
@Component
public class TestAop {
//定义一个方法, 用于声明切入点表达式. 一般地, 该方法中再不需要添入其他的代码。
//使用 @Pointcut 来声明切入点表达式。
//后面的其他通知直接使用方法名来引用当前的切入点表达式。
//(..)表示任意参数
@Pointcut("execution(public * com.example.demo.web..*.*(..))")
public void testAop() {
}
//前置通知:在方法执行前通知
@Before("testAop()")
public void beforeMethod(JoinPoint joinPoint) {
String methodName = joinPoint.getSignature().getName();
Object[] args = joinPoint.getArgs();
System.out.println(String.format("beforeMethod方法名称:%s,方法入参:%s", methodName, joinPoint.getArgs()));
}
//方法执行后通知: 在目标方法执行后无论是否发生异常,执行通知,不能访问目标方法的执行的结果。
@After("testAop()")
public void afterMethod(JoinPoint joinPoint) {
String methodName = joinPoint.getSignature().getName();
System.out.println(String.format("afterMethod方法名称:%s", methodName));
}
//后置通知:在方法正常执行完成进行通知,可以访问到方法的返回值的。
@AfterReturning(value = "testAop()", returning = "result")
public void afterReturning(JoinPoint joinPoint, Object result) {
String methodName = joinPoint.getSignature().getName();
System.out.println(String.format("afterReturning方法名称:%s,方法出参:%s", methodName, result));
}
//异常通知:在方法出现异常时进行通知,可以访问到异常对象,且可以指定在出现特定异常时在执行通知。
@AfterThrowing(value = "testAop()", throwing = "e")
public void afterThrowing(JoinPoint joinPoint, Exception e) {
String methodName = joinPoint.getSignature().getName();
System.out.println(String.format("afterThrowing方法名称:%s,异常参数:%s", methodName, e));
}
//环绕通知:可以将要执行的方法(point.proceed())进行包裹执行,可以在前后添加需要执行的操作
@Around("testAop()")
public Object around(ProceedingJoinPoint point) throws Throwable {
System.out.println("环绕通知开始,方法入参:" + point.getArgs());
Object result = point.proceed();
System.out.println("环绕通知结束,方法返回参数:" + result);
return result;
}
}
3、测试代码
@RestController
public class HomeController {
@RequestMapping("/index")
public String index() throws Exception {
System.out.println("控制器内部方法执行");
TimeUnit.SECONDS.sleep(1);
//int a = 1 / 0;
return "返回页面";
}
}
注意区分@After和@AfterReturning区别,After不论方法是否执正常结束都会通知,而AfterReturning出现异常未正常结束则不会通知。
4. 对接口请求进行简单的封装例子
@Aspect
@Component
@Slf4j
public class WebLogAspect {
@Pointcut("execution(public * com.example.demo.web..*.*(..))")
public void webLog() {
}
//aop环绕通知拦截来搞一下
@Around("webLog()")
public Object around(ProceedingJoinPoint point) throws Throwable {
//获取请求的类名
String className = point.getTarget().getClass().getName();
//从切面织入点处通过反射机制获取织入点处的方法
MethodSignature signature = (MethodSignature) point.getSignature();
//获取请求的方法名
String methodName = signature.getMethod().getName();
log.info(String.format("类名:%s,方法名:%s,入参:%s", className, methodName, JsonHelper.ConvertToJson(point.getArgs())));
StopWatch watch = new StopWatch();
watch.start();
//执行方法
Object result = point.proceed();
watch.stop();
log.info(String.format("类名:%s,方法名:%s,耗时:%s,出参:%s", className, methodName, watch.getLastTaskTimeMillis(), JsonHelper.ConvertToJson(result)));
return result;
}
}
5.获取方法名称的另一种方法:
// An highlighted block
point.getSignature().getName()