Spring Boot 学习之路八,AOP统一处理请求日志

AOP统一处理请求日志

AOP为Aspect Oriented Programming的缩写,意为:[面向切面编程]
理论就不说了,直接上代码吧,呵呵~

注解 用途
@Aspect 注解将一个java类定义为切面类
@Pointcut 定义一个切入点,可以是一个规则表达式,比如下例中某个package下的所有函数,也可以是一个注解等。根据需要在切入点不同位置的切入内容
@Before 在切入点开始处切入内容
@After在 切入点结尾处切入内容
@AfterReturning 在切入点return内容之后切入内容(可以用来对处理返回值做一些加工处理)
@Around在切入 点前后切入内容,并自己控制何时执行切入点自身的内容
@AfterThrowing 用来处理当切入内容部分抛出异常之后的处理逻辑

一、先建一个切面类文件吧

1.在包目录右键-New-Aspect

Spring Boot 学习之路八,AOP统一处理请求日志_第1张图片
建切面类1.png

2.然后会弹出框,输出类名,下方选择框一定要选 @Aspect,如下图:
Spring Boot 学习之路八,AOP统一处理请求日志_第2张图片
建切面类2.png

3.工程目录如下:
Spring Boot 学习之路八,AOP统一处理请求日志_第3张图片
工程目录.png

二、代码

  1. 切面类的代码
@Aspect
@Component
public class TestAspect {

 @Before("execution(public * com.alun.Controller.TestController.*(..))")
    public  void onTestBefore(){
        System.out.print("-------------------------------------------调用前\n");
    }

 @After("execution(public * com.alun.Controller.TestController.*(..))")
    public  void onTestAfter(){
        System.out.print("--------------------------------------------调用后\n");
    }
}
  1. Controller的代码
@RestController
public class TestController {
    @GetMapping("/firstTest")
    public  String getFirst(){
        System.out.print("-----------------我被调用了---------------\n");
        return "你好!";
    }
}
  1. 运行结果
Spring Boot 学习之路八,AOP统一处理请求日志_第4张图片
运行结果1.png
运行结果2.png

4.打印相关信息

@Aspect
@Component
public class TestAspect {

    private final static Logger logger = LoggerFactory.getLogger(TestAspect.class);

    @Pointcut("execution(public * com.alun.Controller.TestController.*(..))")
    public void testLog() {
    }

    @Before("testLog()")
    public void onTestBefore(JoinPoint joinPoint) {

        logger.info("-------------------------------------------调用前\n");
        //记录http请求
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
        //从request中获取http请求的url

        logger.info("url={}", request.getRequestURI());

        ///请求的方法类型
        logger.info("method={}", request.getMethod());

        //IP地址
        logger.info("ip={}", request.getRemoteAddr());

        //响应该http请求的类方法
        logger.info("class_method={}", joinPoint.getSignature().getDeclaringTypeName() +
                "." + joinPoint.getSignature().getName());

        //请求中的参数
        logger.info("args={}", joinPoint.getArgs());

    }

    @AfterReturning(returning = "object", pointcut = "testLog()")
    public void doAfterReturning(Object object) {
        logger.info("响应内容={}", object);
    }

    @After("testLog()")
    public void onTestAfter() {
        logger.info("--------------------------------------------调用后\n");
    }
}
  • 这里使用了org.slf4j.Logger打印日志,可以输出更多信息,如时间和相关类
  • @Before和@After等括号的内容都一样,可以提炼出来,使用@Pointcut实现
  • @Pointcut的使用:
    格式:
execution(modifiers-pattern? ret-type-pattern declaring-type-pattern? name-pattern(param-pattern)throws-pattern?) 

括号中各个pattern分别表示:

  • 修饰符匹配(modifier-pattern?)
  • 返回值匹配(ret-type-pattern)可以为*表示任何返回值,全路径的类名等
  • 类路径匹配(declaring-type-pattern?)
  • 方法名匹配(name-pattern)可以指定方法名 或者 代表所有, set 代表以set开头的所有方法
  • 参数匹配((param-pattern))可以指定具体的参数类型,多个参数间用“,”隔开,各个参数也可以用“”来表示匹配任意类型的参数,如(String)表示匹配一个String参数的方法;(,String) 表示匹配有两个参数的方法,第一个参数可以是任意类型,而第二个参数是String类型;可以用(..)表示零个或多个任意参数
  • 异常类型匹配(throws-pattern?)
    其中后面跟着“?”的是可选项
    这段内容来至于这里

运行结果:


Spring Boot 学习之路八,AOP统一处理请求日志_第5张图片
运行结果

AOP切面的优先级

由于通过AOP实现,程序得到了很好的解耦,但是也会带来一些问题,比如:我们可能会对
Web层做多个切面,校验用户,校验头信息等等,这个时候经常会碰到切面的处理顺序问题。

所以,我们需要定义每个切面的优先级,我们需要@Order(i)注解来标识切面的优先级。i的值越> > 小,优先级越高。假设我们还有一个切面是CheckNameAspect用来校验name必须为didi,我们
为其设置@Order(10),而上文中WebLogAspect设置为@Order(5),所以WebLogAspect有更高
的优先级,这个时候执行顺序是这样的:

在@Before中优先执行@Order(5)的内容,再执行@Order(10)的内容
在@After和@AfterReturning中优先执行@Order(10)的内容,再执行@Order(5)的内容
所以我们可以这样子总结:

在切入点前的操作,按order的值由小到大执行
在切入点后的操作,按order的值由大到小执行

这段内容来至于这里

你可能感兴趣的:(Spring Boot 学习之路八,AOP统一处理请求日志)