美文网首页
spring-boot AOP

spring-boot AOP

作者: 破地瓜 | 来源:发表于2018-09-21 17:26 被阅读20次

    目的:记录所有请求,了解各种通知的调用顺序

    注解说明

    注解 说明 备注
    @Aspect 把当前类标识为一个切面供容器读取
    @Pointcut 切面 定义一个切面
    @Before 前置通知 在调用一个方法前执行
    @After 后置通知 在调用一个方法后执行
    @AfterReturning 后置通知 在调用一个方法后,且该方法无异常时执行
    @AfterThrowing 后置通知 在调用一个方法后,且该方法有异常时执行
    @Around 环绕通知 在调用一个方法前后均执行

    @Pointcut的用法

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

    定义一个aop,用来拦截所有的Controller

    package com.example.demo;
    
    import java.util.Arrays;
    
    import javax.servlet.http.HttpServletRequest;
    
    import lombok.extern.slf4j.Slf4j;
    import org.aspectj.lang.JoinPoint;
    import org.aspectj.lang.ProceedingJoinPoint;
    import org.aspectj.lang.annotation.*;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.stereotype.Component;
    import org.springframework.web.context.request.RequestContextHolder;
    import org.springframework.web.context.request.ServletRequestAttributes;
    
    @Aspect
    @Component
    @Slf4j
    public class ControllerAspect{
    
        @Pointcut("execution(public * com.example..controller.*.*(..))")
        public void excudeService(){
    
        }
        
        @Around("excudeService()")
        public Object doAround(ProceedingJoinPoint pjp) throws Throwable{
            log.info("doAround start ...");
            Object result = pjp.proceed();
            log.info("doAround end ...");
            return result;
        }
        
        @Before("excudeService()")
        public void doBefore(JoinPoint joinPoint) throws Throwable{
            log.info("doBefore start ...");
            ServletRequestAttributes attributes =
                                                (ServletRequestAttributes)RequestContextHolder.getRequestAttributes();
            HttpServletRequest request = attributes.getRequest();
            log.info("method-type: {},uri:{},class:{},method:{},args:{}",
                        request.getMethod(),
                        request.getRequestURI(),
                        joinPoint.getSignature().getDeclaringTypeName(),
                        joinPoint.getSignature().getName(),
                        Arrays.toString(joinPoint.getArgs()));
            log.info("doBefore end ...");
        }
        
        @AfterReturning(returning = "retVal", pointcut = "excudeService()")
        public void doAfterReturning(JoinPoint joinPoint,
                                     Object retVal) throws Throwable{
            log.info("doAfterReturning ...");
            log.info("result:{}", retVal);
        }
    
       @AfterThrowing(pointcut="excudeService()",throwing = "e")
        public void doAfterThrowing(JoinPoint point,Exception e) throws Throwable{
            log.info("doAfterThrowing ...");
            log.info("error:{}", e.getMessage());
        }
        @After("excudeService()")
        public void doAfter(JoinPoint point) throws Throwable{
            log.info("doAfter ...");
        }
    }
    

    定义一个Controller

    package com.example.demo.controller;
    
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    /**
     * @auther jiabiaoli@boco.com.cn
     * @date 2018/9/21 16:22
     */
    @RestController
    public class TestController {
        @GetMapping("/test")
        public String test(){
    
            return "ok";
        }
        @GetMapping("/print")
        public String testError(){
            if(true){
                throw new RuntimeException("exception ...");
            }
            return "ok";
        }
    }
    

    访问http://localhost:8080/test,无异常

    2018-09-21 17:15:03.095  INFO 6648 --- [nio-8080-exec-2] com.example.demo.ControllerAspect        : doAround start ...
    2018-09-21 17:15:03.096  INFO 6648 --- [nio-8080-exec-2] com.example.demo.ControllerAspect        : doBefore start ...
    2018-09-21 17:15:03.097  INFO 6648 --- [nio-8080-exec-2] com.example.demo.ControllerAspect        : method-type: GET,uri:/test,class:com.example.demo.controller.TestController,method:test,args:[]
    2018-09-21 17:15:03.097  INFO 6648 --- [nio-8080-exec-2] com.example.demo.ControllerAspect        : doBefore end ...
    2018-09-21 17:15:03.102  INFO 6648 --- [nio-8080-exec-2] c.e.demo.controller.TestController       : test ...
    2018-09-21 17:15:03.102  INFO 6648 --- [nio-8080-exec-2] com.example.demo.ControllerAspect        : doAround end ...
    2018-09-21 17:15:03.102  INFO 6648 --- [nio-8080-exec-2] com.example.demo.ControllerAspect        : doAfter ...
    2018-09-21 17:15:03.102  INFO 6648 --- [nio-8080-exec-2] com.example.demo.ControllerAspect        : doAfterReturning ...
    2018-09-21 17:15:03.102  INFO 6648 --- [nio-8080-exec-2] com.example.demo.ControllerAspect        : result:ok
    

    结论

    • 第一步:执行Around的前半段
    • 第二步:执行Before
    • 第三步:执行Controller中对应的方法
    • 第四步:执行doAround的后半段
    • 第五步:执行doAfter
    • 第六步:执行doAfterReturning

    访问http://localhost:8080/print,有异常

    2018-09-21 17:16:24.190  INFO 6648 --- [nio-8080-exec-4] com.example.demo.ControllerAspect        : doAround start ...
    2018-09-21 17:16:24.190  INFO 6648 --- [nio-8080-exec-4] com.example.demo.ControllerAspect        : doBefore start ...
    2018-09-21 17:16:24.190  INFO 6648 --- [nio-8080-exec-4] com.example.demo.ControllerAspect        : method-type: GET,uri:/print,class:com.example.demo.controller.TestController,method:testError,args:[]
    2018-09-21 17:16:24.191  INFO 6648 --- [nio-8080-exec-4] com.example.demo.ControllerAspect        : doBefore end ...
    2018-09-21 17:16:24.191  INFO 6648 --- [nio-8080-exec-4] c.e.demo.controller.TestController       : test error ...
    2018-09-21 17:16:24.191  INFO 6648 --- [nio-8080-exec-4] com.example.demo.ControllerAspect        : doAfter ...
    2018-09-21 17:16:24.191  INFO 6648 --- [nio-8080-exec-4] com.example.demo.ControllerAspect        : doAfterThrowing ...
    2018-09-21 17:16:24.191  INFO 6648 --- [nio-8080-exec-4] com.example.demo.ControllerAspect        : error:exception ...
    

    结论

    • 第一步:执行Around的前半段
    • 第二步:执行Before
    • 第三步:执行Controller中对应的方法
    • 第四步:执行Around的后半段
    • 第五步:执行After
    • 第六步:执行AfterThrowing

    无论是否有错误,After均会执行

    相关文章

      网友评论

          本文标题:spring-boot AOP

          本文链接:https://www.haomeiwen.com/subject/zpfznftx.html