什么是aop

aop(Aspect Oriented Programming)面向切面编程,一种可以在运行时在被调用的方法前后动态织入代码的编程方式。

相关术语
  • Aspect: 切面,包含一些Pointcut和Advice
  • Pointcut:切入点,相当于一个条件,只有符合条件的方法才会走Advice
  • advice:通知,只有符合Pointcut的方法会执行通知,advice分为before,around,after,AfterReturning,AfterThrowing
  • advice通过以下几种通知来确定在什么时候调用advice
    • @before:前置通知,方法执行之前调用advice
    • @around:环绕通知,方法执行前后都会调用advice
    • @after:后置通知,方法执行之后调用advice(无论方法执行是否发送异常,总是调用)
    • @AfterReturning:后置通知,方法执行之后调用advice,可以获取返回值 (无论方法执行是否发送异常,总是调用)
    • @AfterThrowing:后置通知,方法执行中发生异常后调用,可以获取异常信息(只有发生异常才会)

集成aop

  • 新建一个springboot项目
  • pom.xml中引入aop依赖
引入依赖

新建项目后,在pom.xml中引入aop依赖 spring-boot-starter-aop ,pom.xml完整依赖如下:

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-aop</artifactId>
    </dependency>
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <version>1.16.22</version>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
</dependencies>
编写切面
/**
 * @auther: chenmingyu
 * @date: 2018/12/5 17:26
 * @description:
 */
@Aspect
@Component
public class TestAspect {

    /**
     * 切入点
     */
    @Pointcut("execution(public * com.my.aop.controller.*.*(..))")
    public void execute(){
    }

    /**
     * 前置通知
     * @param joinPoint
     */
    @Before(value ="execute()")
    public void Before(JoinPoint joinPoint) {
        System.out.println("执行方法之前");
    }

    /**
     * 环绕通知
     * @param proceedingJoinPoint
     * @return
     */
    @Around(value ="execute()")
    public Object around(ProceedingJoinPoint proceedingJoinPoint) {
        System.out.println("环绕通知开始");
        try {
            System.out.println("执行方法:" + proceedingJoinPoint.getSignature().getName());
            Object object =  proceedingJoinPoint.proceed();
            System.out.println("环绕通知结束,方法返回:" + object);
            return object;
        } catch (Throwable e) {
            System.out.println("执行方法异常:" + e.getClass().getName());
            return null;
        }
    }

    /**
     * 后置通知
     * @param joinPoint
     */
    @After(value ="execute()")
    public void After(JoinPoint joinPoint) {
        System.out.println("执行方法之后");
    }

    /**
     * 后置通知,带返回值
     * @param obj
     */
    @AfterReturning(pointcut = "execute()",returning = "obj")
    public void AfterReturning(Object obj) {
        System.out.println("执行方法之后获取返回值:"+obj);
    }

    /**
     * 后置通知,异常时执行
     * @param e
     */
    @AfterThrowing(throwing = "e",pointcut = "execute()")
    public void doAfterThrowing(Exception e) {
        System.out.println("执行方法异常:"+e.getClass().getName());
    }
}

@Aspect :声明这个类是一个切面

@Component:将bean交由spring管理

@Pointcut(“execution(public com.my.aop.controller..*(..))”):声明切入点

execution(public com.my.aop.controller..*(..)):条件表达式,之后com.my.aop.controller包下的public声明的方法会走通知

@Before,@Around,@After,@AfterReturning,@AfterThrowing:通知类型

验证Aspect
/**
 * @auther: chenmingyu
 * @date: 2018/12/5 17:34
 * @description:
 */
@RestController
public class AspectController {

    /**
     * 走切面
     * @return
     */
    @GetMapping("/test")
    public String test(){
        return "method return";
    }

    /**
     * 不走切面
     */
    @GetMapping("/test1")
    private void test1(){
    }

    /**
     * 走切面,抛异常
     */
    @GetMapping("/throws")
    public void throwsException(){
        throw new RuntimeException();
    }
}

执行 http://localhost:8080/test1,没有输出

执行 http://localhost:8080/test,输出如下

执行 http://localhost:8080/throws,输出如下