Fork me on GitHub

Spring AOP 机制总结

寄语:刚开始学aop的时候是大三吧,老师讲的不好,我也没学好,导致现在才有个较为清晰的认知,那个时候只知道有aop,

根部不明白aop的作用,时至今日,任然觉得aop难以咀嚼,奈何平时不用面试要用,特此总结。

下面开始总结:

注意:我使用的是springboot2.1+maven3.6,请自行搭建基础环境

项目github地址:https://github.com/zgq7/devloper-mine/blob/master/src/main/java/com/dev/config/aop/BaseAop.java

1:导入maven依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-aop</artifactId>
    <version>2.1.6.RELEASE</version>
</dependency>

2:切面类

package com.dev.config.aop;

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.core.annotation.Order;

import java.util.Collections;

/**
 * Created by zgq7 on 2019/7/12.
* * 各通知执行顺序: * 1:around-> * 2:before-> * 3:around->retrun code -> * 4:after-> * 5:afterReturning-> * 6:afterThrowing * </p> * <p> * order 执行顺序: * 1:进入目的方法时:order值越小越先执行 * 2:从目的方法出去时:order值越大越先执行 * </p>
*/ @Aspect @Order(1) public class BaseAop { private final Logger log = LoggerFactory.getLogger(this.getClass()); /** * 写入具体切面点 * * @apiNote execution 路径中的 "." 如果是精确到类,则一个就行,如果是精确到包就得两个 "." * @apiNote execution 路径若只精确到包,就无法使用 before、after、afterReturuning、around 四个通知模块,启动会报错 **/ @Pointcut("execution(public * com.dev.controller.TestController.s())") public void aspect() { } /** * 进入方法体前 **/ @Before(value = "aspect()") public void before(JoinPoint joinPoint) { log.info("before :参数类型:{}", joinPoint.getArgs()); } /** * 该切面返回数据前(在retrun之前执行) **/ @After(value = "aspect()") public void after(JoinPoint joinPoint) { log.info("aop before return :{}", joinPoint.toLongString()); } /** * 该切面返回数据后 * joinPoint.getSignature() 返回方法放回类型 及 方法路径 **/ @AfterReturning(value = "aspect()", returning = "result") public void afterReturning(Object result) { log.info("aop after return :返回结果:{}", result); } /** * 环绕通知 * 1:before之前 * 2:afterReturning之后 * * @apiNote 1:@Around 下接的方法的参数必须为 ProceedingJoinPoint 类型, * @apiNote 2:proceedingJoinPoint.proceed() 产生的结果即为 @AfterReturning 中的 result,可 debug 调试 * @apiNote 3:由于@Around要提前获取到目的方法的执行结果,且@Around提前于@AfterThrowing运行,因此异常将在@Around中被捕获,从而导致@AfterThrowing捕获不到异常,因此@Around与@AfterThrowing混合使用 **/ //@Around(value = "aspect()") public Object around(ProceedingJoinPoint proceedingJoinPoint) { log.info("aop arrounding :{}", proceedingJoinPoint.getSignature().getName()); try { return proceedingJoinPoint.proceed(); } catch (Throwable throwable) { log.info("aop arrounding error :{}", throwable.getMessage()); //throwable.printStackTrace(); return Collections.EMPTY_MAP; } } /** * 切面报错 **/ @AfterThrowing(value = "aspect()", throwing = "exception") public void afterThrowing(Throwable exception) { log.error("exception occured , msg : {}", exception.getMessage()); if (exception instanceof NullPointerException) log.info("空指针异常"); } }

2.1:多个切面的执行顺序

  1:进入目的方法时:order值越小越先执行

  2:从目的方法出去时:order值越大越先执行

notice2.2:aspect 中 @befer、@after、@afterReturning、@around、@afterThrowing的执行顺序

 * 1:around->
 * 2:before->
 * 3:around->retrun code ->
 * 4:after->
 * 5:afterReturning
notice2.2.1:各项通知也严格按照order的值进行传递一层一层的走下去

notice2.3:aspect 中@around 下属的方法必须要有返回值,否则就是一个 “有问题” 的切面

 * @apiNote 1:@Around 下接的方法的参数必须为 ProceedingJoinPoint 类型,
 * @apiNote 2:proceedingJoinPoint.proceed() 产生的结果即为  @AfterReturning 中的 result,可 debug 调试

notice2.4:aspect 中@around 不能与 @afterThrowing 混用

 * @apiNote 3:由于@Around要提前获取到目的方法的执行结果,且@Around提前于@AfterThrowing运行,因此异常将在@Around中被捕获,从而导致@AfterThrowing捕获不到异常,因此@Around与@AfterThrowing混合使用

notice2.5:aspect 中@PointCut中的execution类路径或者包路径问题

 * @apiNote execution 路径中的 "." 如果是精确到类,则一个就行,如果是精确到包就得两个 "."
 * @apiNote execution 路径若只精确到包,就无法使用 before、after、afterReturuning、around 四个通知模块,启动会报错
posted @ 2019-08-06 16:52  竹根七  阅读(896)  评论(0编辑  收藏  举报