SpringBoot面向切面编程(AOP)

Aspect

(与SpringBoot整合)

总结

  1. 作用位置

    try{
    	try{
    		@Around 前置环绕通知
    		@Before 前置通知
    		method.invoke(..);
           }catch(){
            @AfterThrowing 异常通知
    		throw.....;
       }finally{
    		@After 后置通知
       }
    	@AfterReturning 返回通知
    }finally{
        @Around 后置环绕通知
    }
    
  2. 执行流程

    1. 正常情况: @Around ==> @Before ==> 目标方法 ==> @After ==> @AfterReturning ==> @Around;
    2. 异常情况: @Around ==> @Before ==> 目标方法(出现异常) ==> @AfterThrowing ==> @After ==> @Around;

代码演示

1. 引入aop依赖

pom.xml

        <!--    引入AOP依赖    -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
        </dependency>

2. 核心业务类

Service层

UserService.java

@Service
public class UserService {

 public void service1(){
     System.out.println("Service-1-执行");
 }

 public String service2(){
     System.out.println("Service-2-执行");
     //int i = 1/0;  //异常测试
     return "Success!!!";
 }

 public ArrayList<String> service3(String userName){
     System.out.println("Service-3-执行");
     ArrayList<String> list = new ArrayList<>();
     list.add("Service-3-执行成功!!!");
     list.add(userName);
     return list;
 }

}

3. 切面

MyAspect.java

注:一定要将切面作为Spring组件注入容器

@Component
@Aspect
public class MyAspect {

    //定义切入点
    @Pointcut("within(com.juyss.service.*)")
    public void pointcut(){}

    //环绕通知 ===> 正常情况执行在@Before和@After之前,如果执行过程中抛异常,只执行前置环绕通知,后置环绕不执行
    @Around(value = "pointcut()")
    public Object around(ProceedingJoinPoint point){
        System.out.println("前置环绕通知!!!");
        Object proceed = null;
        try {
            System.out.println("point.proceed()执行前----------------------------");
            Signature signature = point.getSignature();
            System.out.println("获取类名:"+signature.getName());
            System.out.println("point.proceed()执行前----------------------------");
            proceed = point.proceed();
            System.out.println("point.proceed()执行后----------------------------");
            System.out.println("获取返回值:"+proceed);
            System.out.println("point.proceed()执行后----------------------------");
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }
        System.out.println("后置环绕通知!!!");
        return proceed;
    }

    //前置通知 ===> 方法执行前
    @Before("pointcut()")
    public void before(){
        System.out.println("前置通知生效!!!");
    }

    //返回通知 ===> 方法正常执行完后执行,可以获取返回值.如果方法执行过程中抛异常,则不会执行
    @AfterReturning(value = "pointcut()",returning = "returnValue")
    public void afterReturning(Object returnValue){
        System.out.println("返回通知生效!!! ------返回值:"+returnValue);
    }

    //后置通知 ===> 在finally代码块中执行,无论如何都会执行的通知
    @After("pointcut()")
    public void after(JoinPoint joinPoint){
        Signature signature = joinPoint.getSignature();
        System.out.println("后置通知生效!!! ------ 方法名:"+signature.getName());
    }

    //异常通知 ===> 在执行过程中抛出异常时执行
    @AfterThrowing(value = "pointcut()",throwing = "e")
    public void afterThrowing(Exception e){
        System.out.println("异常通知生效!!! 异常信息:"+e.getMessage());
    }
}

4. 测试类

AspectApplicationTests.java

@SpringBootTest
class AspectApplicationTests {

    @Autowired
    private UserService service;

    @Test
    public void Test(){
        service.service1();
        System.out.println("************************************************************************");
        service.service2();
        System.out.println("************************************************************************");
        service.service3("方法参数");
        System.out.println("************************************************************************");
    }

}

5. 测试结果

正常运行时:

前置环绕通知!!!
point.proceed()执行前----------------------------
获取类名:service1
point.proceed()执行前----------------------------
前置通知生效!!!
Service-1-执行
返回通知生效!!! ------返回值:null
后置通知生效!!! ------ 方法名:service1
point.proceed()执行后----------------------------
获取返回值:null
point.proceed()执行后----------------------------
后置环绕通知!!!
************************************************************************************************
前置环绕通知!!!
point.proceed()执行前----------------------------
获取类名:service2
point.proceed()执行前----------------------------
前置通知生效!!!
Service-2-执行
返回通知生效!!! ------返回值:Success!!!
后置通知生效!!! ------ 方法名:service2
point.proceed()执行后----------------------------
获取返回值:Success!!!
point.proceed()执行后----------------------------
后置环绕通知!!!
************************************************************************************************
前置环绕通知!!!
point.proceed()执行前----------------------------
获取类名:service3
point.proceed()执行前----------------------------
前置通知生效!!!
Service-3-执行
返回通知生效!!! ------返回值:[Service-3-执行成功!!!, 方法参数]
后置通知生效!!! ------ 方法名:service3
point.proceed()执行后----------------------------
获取返回值:[Service-3-执行成功!!!, 方法参数]
point.proceed()执行后----------------------------
后置环绕通知!!!
************************************************************************************************

方法运行抛出异常时

前置环绕通知!!!
point.proceed()执行前----------------------------
获取类名:service1
point.proceed()执行前----------------------------
前置通知生效!!!
Service-1-执行
返回通知生效!!! ------返回值:null
后置通知生效!!! ------ 方法名:service1
point.proceed()执行后----------------------------
获取返回值:null
point.proceed()执行后----------------------------
后置环绕通知!!!
************************************************************************************************
前置环绕通知!!!
point.proceed()执行前----------------------------
获取类名:service2
point.proceed()执行前----------------------------
前置通知生效!!!
Service-2-执行
异常通知生效!!! 异常信息:/ by zero
后置通知生效!!! ------ 方法名:service2
java.lang.ArithmeticException: / by zero
	at com.juyss.service.UserService.service2(UserService.java:25)
	##############其他异常信息省略################
后置环绕通知!!!
************************************************************************************************
前置环绕通知!!!
point.proceed()执行前----------------------------
获取类名:service3
point.proceed()执行前----------------------------
前置通知生效!!!
Service-3-执行
返回通知生效!!! ------返回值:[Service-3-执行成功!!!, 方法参数]
后置通知生效!!! ------ 方法名:service3
point.proceed()执行后----------------------------
获取返回值:[Service-3-执行成功!!!, 方法参数]
point.proceed()执行后----------------------------
后置环绕通知!!!
************************************************************************************************
原文地址:https://www.cnblogs.com/juyss/p/14099422.html