七、SpringBoot入门之使用AOP处理请求

(一)前期准备
  添加POM依赖:

        <!--aop-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
        </dependency>

(二)使用
  1.在GirlController类中的所有方法调用之前调用“开始记录日志”这句话

@Component
@Aspect
public class HttpAspect {
    /**
     * 拦截GirlController类中的所有方法
     * 方法详解:
     * “@Before”:在拦截的目标方法之前调用标注有该注解的方法
     *  "execution(public * org.pc.girl.controller.GirlController.*(..))":execution表达式
     *      public * org.pc.girl.controller.GirlController.*(..)
     *          public:目标方法的访问权限
     *          *     :目标方法的返回类型(*是通配符,所有类型都行)
     *          org.pc.girl.controller.GirlController:目标方法所在的类,必须是全限定名
     *          *     :目标方法名,若是通配符“*”,则拦截所有方法;若是某个方法名,则只拦截这个方法,比如只拦截
     *                  删除方法(removeGirl()),那就得写成“removeGirl”
     *          (..)  :目标方法的参数
     */
    @Before("execution(public * org.pc.girl.controller.GirlController.*(..))")
    public void logAll(){
        System.out.println("开始记录日志");
    }
}

  2.在GirlController类中的所有方法调用之后调用“结束记录日志”这句话

    @After("execution(public * org.pc.girl.controller.GirlController.*(..))")
    public void logAfter(){
        System.out.println("结束记录日志");
    }

  问题:此时就会发现“execution”表达式重复了,这样反复调用这么一长串的代码,一旦我们需要对“execution”表达式进行更改,那么就需要做大量的重复劳动,而且非常有可能出错,怎么办?

  解决办法:定义一个切点“@Pointcut”,标注在一个公用方法之上,然后复用公用方法:

@Pointcut("execution(public * org.pc.girl.controller.GirlController.*(..))")
    public void log(){

    }
    @Before("log()")
    public void logBefore(){
        System.out.println("开始记录日志");
    }

    @After("log()")
    public void logAfter(){
        System.out.println("结束记录日志");
    }

  3.在切面方法中获取所拦截方法的请求信息和被拦截类、方法信息

  (1)获取所拦截方法的请求信息和被拦截类、方法信息

    @Before("log()")
    public void logBefore(JoinPoint joinPoint){
        System.out.println("开始记录日志");
        //获取请求对象
        ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        if (requestAttributes != null){
            HttpServletRequest request = requestAttributes.getRequest();
            //获取请求url
            LOGGER.info("url={}", request.getRequestURI());
            //获取请求方法
            LOGGER.info("method={}", request.getMethod());
            //获取请求ip
            LOGGER.info("ip={}", request.getRemoteAddr());
            //获取请求端口
            LOGGER.info("port={}", request.getServerPort());
        }
        /*----------------------- 获取拦截的类信息、方法信息的关键参数是JoinPoint对象 ----------------------------*/
        //获取拦截类名
        String className = joinPoint.getSignature().getDeclaringTypeName();
        LOGGER.info("class={}", className);
        //获取拦截类下的方法名
        String methodName = joinPoint.getSignature().getName();
        LOGGER.info("method={}", methodName);
        //获取拦截的方法的参数
        Object[] params = joinPoint.getArgs();
        LOGGER.info("params={}", params);
    }

  (2)获取所拦截方法的返回值

    /**
     * 获取拦截方法的返回值
     * “@AfterReturning”:先执行“@After”,再执行“@AfterReturning”
     *     “returning”:返回值将注入到哪个变量中
     *     “pointcut” :切点
     *  Object object:和“returning”规定的字段相同,才能保证方法的返回值会注入到该变量中
     */
    @AfterReturning(returning = "object", pointcut = "log()")
    public void doAfter(Object object){
        LOGGER.info("response={}", object.toString());
    }

  (3)@Around注解
  @Around注解既可在@Before之前执行,又可同时在原方法执行之后,@After执行方法之前执行。代码如下:

    /**
     *     pjp.proceed()执行之后得到的返回值就是所拦截方法执行之后的返回值,若在这里不返回pjp.proceed(),那么方法将
     * 不再有返回值。比如,我们在“@AfterReturning”标注的方法中,就无法得到方法的返回值,会报空指针异常!
     */
    @Around("log()")
    public Object doAround(ProceedingJoinPoint pjp) throws Throwable {
        //在“@Before”标注的拦截方法之前执行
        LOGGER.info("调用了环绕方法");
        //执行原方法,返回原方法的返回值
        Object object = pjp.proceed();
        //在被拦截的方法执行之后,“@After”标注的拦截方法之前执行
        LOGGER.info("又调用了环绕方法");
        return object;
    }

  pjp.proceed()之前的逻辑在“@Before”之前执行,pjp.proceed()之前的逻辑在原方法执行之后,“@After”之前执行。
  注意:pjp.proceed()这里执行的逻辑就是执行原方法,返回值也就是原方法的返回值,若我们还希望对原方法的返回值进行处理,那么我们就必须return pjp.proceed(),否则后续我们将无法取到方法的返回值!!!

(三)关于AOP中各个注解的生命周期
  AOP中共有4个注解:@Before、@After、@AfterReturning、@Around四大注解,他们的的生命周期如下:
    第一步:执行@Around
    第二步:执行@Before
    第三步:执行原方法
    第四步:执行@Around
    第五步:执行@After
    第六步:执行@AfterReturning

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值