美文网首页
Spring中切面详解(AOP)

Spring中切面详解(AOP)

作者: i小雨 | 来源:发表于2021-01-05 10:52 被阅读0次

    注意:下面的测试是spring4版本,spring5的执行顺序有变化,请看

    1、操作术语:

    • 连接点:
      类里面哪些方法可以被增强,这些方法称为连接点
    • 切入点:
      实际被真正增强的方法,称为切入点
    • 通知(增强):
      1、实际增强的逻辑部分称为通知(增强)
      2、通知的种类:
      • 前置通知——@Before()
      • 后置通知——@AfterReturning() (也叫做返回通知)
      • 环绕通知——@Around
      • 异常通知——@AfterThrowing()
      • 最终通知——@After()(相当于finally)
    • 切面:
      把通知应用到切入点的过程叫做切面

    2、切入点表达式:

    语法:execution( [权限修饰符] [返回类型] [方法名称] ([参数列表]))

    • 举例1:对com.yy.test.BookService类里的add方法增强
      execution(* com.yy.test.BookService.add(..))
    • 举例2:对com.yy.test.BookService类里的所有方法增强
      execution(* com.yy.test.BookService.*(..))
    • 举例3:对com.yy.test包里的所有类的所有方法增强
      execution(* com.yy.test. * . * (..))
      返回类型可以省略

    3、@Aspect注解用法:

    1. 环境:
      • 引入依赖:
        <dependency>
              <groupId>org.aspectj</groupId>
              <artifactId>aspectjweaver</artifactId>
              <version>1.9.5</version>
          </dependency>
        
      • 开启包扫描和@Aspect注解
        <?xml version="1.0" encoding="UTF-8"?>
        <beans xmlns="http://www.springframework.org/schema/beans"
                xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                xmlns:context="http://www.springframework.org/schema/context"
                xmlns:aop="http://www.springframework.org/schema/aop"
                xsi:schemaLocation="http://www.springframework.org/schema/beans
                http://www.springframework.org/schema/beans/spring-beans.xsd
                 http://www.springframework.org/schema/context
                 http://www.springframework.org/schema/context/spring-context.xsd
                 http://www.springframework.org/schema/aop
                 http://www.springframework.org/schema/aop/spring-aop.xsd">
            <!--开启包扫描-->
            <context:component-scan base-package="com.yy.aspect"/>
            <!--开启aspectJ注解-->
            <aop:aspectj-autoproxy/>
        </beans>
        
    2. 创建需要增强的的类User和代理类CommonAspect
      User:
    package com.yy.aspect;
    
    import org.springframework.stereotype.Component;
    
    @Component
    public class User {
        public void addUser(){
            System.out.println("成功添加一个用户");
        }
    }
    

    CommonAspect:

    package com.yy.aspect;
    
    import org.aspectj.lang.annotation.Aspect;
    import org.aspectj.lang.annotation.Before;
    import org.springframework.stereotype.Component;
    
    @Component
    @Aspect
    public class CommonAspect {
        //前置通知
        @Before(value = "execution(* com.yy.aspect.User.addUser(..))")
        public void before(){
            System.out.println("前置通知");
        }
        //后置通知(返回结果之后执行)
        @AfterReturning(value = "execution(* com.yy.aspect.User.addUser(..))")
        public void afterReturning(){
            System.out.println("AfterReturning...");
        }
        //最终通知(不管有没有发生异常)
        @After(value = "execution(* com.yy.aspect.User.addUser(..))")
        public void after(){
            System.out.println("最终通知");
        }
    
        //异常通知
        @AfterThrowing(value = "execution(* com.yy.aspect.User.addUser(..))")
        public void afterThrowing(){
            System.out.println("AfterThrowing...");
        }
        //环绕通知
        @Around(value = "execution(* com.yy.aspect.User.addUser(..))")
        public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
            System.out.println("环绕通知前");
            proceedingJoinPoint.proceed();//被增强的方法执行
            System.out.println("环绕通知后");
        }
    }
    
    1. 测试1(程序正常执行):
    package com.yy.test;
    
    import com.yy.aspect.User;
    import org.junit.Test;
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    
    public class TestAspect {
    
        @Test
        public void testMethod(){
            ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");
            User user = applicationContext.getBean(User.class);
            user.addUser();
        }
    }
    

    结果1:可以发现没有异常通知

    环绕通知前
    前置通知
    成功添加一个用户
    环绕通知后
    最终通知
    AfterReturning...
    
    1. 测试1(程序执行异常):
      在User的addUser()方法中增加异常:
    @Component
    public class User {
        public void addUser(){
            int i= 10/0;
            System.out.println("成功添加一个用户");
        }
    }
    

    结果2:

    环绕通知前
    前置通知
    最终通知
    AfterThrowing...
    
    java.lang.ArithmeticException: / by zero
        at com.yy.aspect.User.addUser(User.java:9)
        ......
    

    4. 相同切入点抽取:

    可以发现:上面5中通知类型的切入点表达式都是一样的,于是可以将切入点抽取出来。

    package com.yy.aspect;
    
    import org.aspectj.lang.ProceedingJoinPoint;
    import org.aspectj.lang.annotation.*;
    import org.springframework.stereotype.Component;
    
    @Component
    @Aspect
    public class CommonAspect {
        //抽取相同切入点
        @Pointcut(value = "execution(* com.yy.aspect.User.addUser(..))")
        public void pointCut(){}{}
    
        //前置通知
        @Before(value = "pointCut()")
        public void before(){
            System.out.println("前置通知");
        }
        //后置通知(返回结果之后执行)
        @AfterReturning(value = "pointCut()")
        public void afterReturning(){
            System.out.println("AfterReturning...");
        }
        //最终通知(不管有没有发生异常)
        @After(value = "pointCut()")
        public void after(){
            System.out.println("最终通知");
        }
    
        //异常通知
        @AfterThrowing(value = "pointCut()")
        public void afterThrowing(){
            System.out.println("AfterThrowing...");
        }
        //环绕通知
        @Around(value = "pointCut()")
        public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
            System.out.println("环绕通知前");
            proceedingJoinPoint.proceed();//被增强的方法执行
            System.out.println("环绕通知后");
        }
    }
    

    5. 设置增强类的优先级:

    如果多个增强类对同一个方法(或多个方法)增强,设置增强类的优先级:

    • 在增强类上添加注解@Order(数字),数字越小优先级越高。

    相关文章

      网友评论

          本文标题:Spring中切面详解(AOP)

          本文链接:https://www.haomeiwen.com/subject/bepvoktx.html