【Spring - AOP】--- AOP使用简介

源码地址:https://github.com/nieandsun/spring-study


这周加班好累啊,今天几乎睡了一天,仍然感觉没有歇过来 ::>_<::
但生活还得继续 。。。

1 AOP使用简介

1.1 前期准备

(1) 导包 — > 可以查看本篇文章对应的commit记录

(2) 业务类并将其注入spring容器

  • 业务类
package com.nrsc.springstudy.c10_AOP.service;

import org.springframework.stereotype.Service;
@Service
public class Calculator {
    //业务方法
    public int div(int i, int j) {
        System.err.println("==开始进入div方法===");
        return i / j;
    }
}
  • 配置类
package com.nrsc.springstudy.c10_AOP.config;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
@Configuration
@ComponentScan(value = "com.nrsc.springstudy.c10_AOP")
@EnableAspectJAutoProxy//开启AOP功能
public class C10Config {
}
  • 启动类
import com.nrsc.springstudy.c10_AOP.config.C10Config;
import com.nrsc.springstudy.c10_AOP.service.Calculator;
import org.junit.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class Test10_AOP {
    @Test
    public void test01() {
        AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(C10Config.class);
        Calculator bean = ac.getBean(Calculator.class);
        int div = bean.div(4, 2);
        System.err.println("=====结果为=======" + div);
        ac.close();
    }
}

1.2 切面类开发

package com.nrsc.springstudy.c10_AOP.aop;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

import java.util.Arrays;

/***
 *  前置通知: 在执行目标方法div()之前运行------------------------------------@Before
 *  后置通知: 在目标方法div运行结束之后运行 ,不管有没有异常-------------------@After
 *  返回通知: 在目标方法div正常返回值后运行----------------------------------@AfterReturning
 *  异常通知: 在目标方法div出现异常后运行------------------------------------@AfterThrowing
 *
 *  环绕通知: 需要手动执行joinPoint.procced()(其实就是执行目标方法div,),
 * 						执行joinPoint.procced()之前的方法相当于前置通知,
 * 						执行之后就相当于后置通知----------------------------@Around
 */
@Aspect
@Component
public class LogAspects {

    @Pointcut("execution(public int com.nrsc.springstudy.c10_AOP.service.Calculator.*(..))")
    public void pointCut() {
    }

    @Before("pointCut()") //前置通知
    public void logStart(JoinPoint joinPoint) {
        //获取到请求参数列表
        Object[] args = joinPoint.getArgs();
        //获取到请求方法
        String name = joinPoint.getSignature().getName();
        System.out.println("@Before:当前方法为:" + name + "======参数列表是:" + Arrays.asList(args));
    }

    @After(value = "pointCut()") //后置通知
    public void logEnd(JoinPoint joinPoint) {
        String name = joinPoint.getSignature().getName();
        System.out.println("@After---" + name + "方法结束......");
    }

    @AfterReturning(value = "pointCut()", returning = "result") //返回通知
    public void logReturn(Object result) {
        System.out.println("@AfterReturning---正常返回......运行结果是:{" + result + "}");
    }

    @AfterThrowing(value = "pointCut()", throwing = "exception") //异常通知
    public void logException(Exception exception) {
        System.out.println("@AfterThrowing运行异常......异常信息是:{" + exception + "}");
    }

    @Around("pointCut()") //环绕通知 --- 工作中我习惯用这个
    public Object Around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        System.out.println("@Arount:执行目标方法之前...");
        //相当于开始调div地
        Object obj = proceedingJoinPoint.proceed();
        System.out.println("@Arount:执行目标方法之后...");
        return obj;
    }
}

2 运行结果测试

2.1 目标方法不会发生异常时

启动类中的参数传入的是(4,2)时,运行结果如下图。可以看到各个方法的执行顺序为:

环绕通知 — > 前置通知 —> 目标方法 —> 环绕通知 —> 后置通知 —> 返回通知


由于没有发生异常,所以异常通知没有执行。

在这里插入图片描述

2.2 目标方法发生异常,但环绕通知将异常抛出时

(2)当启动类中的参数传入的是(4,0)时,运行结果如下图。可以看到各个方法的执行顺序为:

环绕通知 — > 前置通知 —> 目标方法 —> 后置通知 —> 异常通知


由于发生了异常,返回通知没有执行


下图中异常通知后打印的的红色内容是环绕通知抛出的Throwable 异常信息。

在这里插入图片描述

2.3 目标方法发生异常,但环绕通知将异常捕获处理时

在1中我把环绕通运行proceed() 方法可能出现的异常给抛了出去,这种情况下会得到2.2中的运行结果,那假如环绕通知将异常捕获并进行处理,会发生什么呢?

  • 环绕通知代码修改
    @Around("pointCut()") //环绕通知 --- 工作中我习惯用这个
    public Object Around(ProceedingJoinPoint proceedingJoinPoint) {
        System.out.println("@Arount:执行目标方法之前...");
        //相当于开始调div地
        Object obj = null;
        try {
            obj = proceedingJoinPoint.proceed();
        } catch (Throwable throwable) {
            System.out.println("@Around运行异常......异常信息是:{" + throwable.getMessage() + "}");
            //throwable.printStackTrace();
        }
        System.out.println("@Arount:执行目标方法之后...");
        return obj;
    }

启动类中的传入的参数仍是(4,0)时,运行结果如下图。可以看到各个方法的执行顺序为:

环绕通知 — > 前置通知 —> 目标方法 —> 环绕通知 —> 后置通知 —> 返回通知


可以看到这时异常通知方法不会运行


但由于返回参数类型不对,仍然发生了信息报错,导致启动类中的 System.err.println("=结果为===" + div);
方法没有运行。

在这里插入图片描述

发布了189 篇原创文章 · 获赞 187 · 访问量 39万+

猜你喜欢

转载自blog.csdn.net/nrsc272420199/article/details/103334911