Lecture12-切面-[实验01]初步实现

文章目录

    [toc]

    单词词性音标含义
    Aspectn./ˈæspekt/切面(Spring AOP核心概念,封装横切关注点(如日志、事务)的模块,由切点(Pointcut)和通知(Advice)组成,用于定义“在何时、何处执行增强逻辑”)
    Beforeprep. / adj./bɪˈfɔː(r)/之前(AOP中的前置通知,用@Before注解标识,指在目标方法执行之前触发的增强逻辑,如参数校验、日志记录开始)
    Afterprep. / adj./ˈɑːftə(r)/之后(AOP中的后置通知,用@After注解标识,指在目标方法执行之后(无论是否抛出异常)触发的增强逻辑,如资源释放)
    Returningv. (现在分词)/rɪˈtɜːnɪŋ/返回(AOP中的返回通知,用@AfterReturning注解标识,指在目标方法正常返回后触发的增强逻辑,可获取返回值,如结果日志)
    Throwingv. (现在分词)/ˈθrəʊɪŋ/抛出(AOP中的异常通知,用@AfterThrowing注解标识,指在目标方法抛出异常后触发的增强逻辑,可捕获异常信息,如错误处理)
    executionn./ˌeksɪˈkjuːʃn/执行(AOP中用于定义切点的表达式关键字,通过execution()指定需要增强的目标方法,如execution(* com.example.service.*.*(..))匹配服务层所有方法)

    Lecture12-切面-[实验01]初步实现

    1、加入依赖

    在 IoC 测试工程环境的基础上,额外再增加下面依赖:

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

    2、准备被代理的目标资源

    ①接口

    public interface Calculator {
        
        int add(int i, int j);
        
        int sub(int i, int j);
        
        int mul(int i, int j);
        
        int div(int i, int j);
        
    }
    

    ②纯净的实现类

    在 Spring 下工作,所有的一切都必须放在 IoC 容器中。现在接口的实现类是 AOP 要代理的目标类,所以它也必须放入 IOC 容器。

    package com.atguigu.aop.impl;
        
    import com.atguigu.aop.api.Calculator;
    import org.springframework.stereotype.Component;
        
    @Component
    public class CalculatorPureImpl implements Calculator {
        
        @Override
        public int add(int i, int j) {
        
            int result = i + j;
        
            System.out.println("方法内部 result = " + result);
        
            return result;
        }
        
        @Override
        public int sub(int i, int j) {
        
            int result = i - j;
        
            System.out.println("方法内部 result = " + result);
        
            return result;
        }
        
        @Override
        public int mul(int i, int j) {
        
            int result = i * j;
        
            System.out.println("方法内部 result = " + result);
        
            return result;
        }
        
        @Override
        public int div(int i, int j) {
        
            int result = i / j;
        
            System.out.println("方法内部 result = " + result);
        
            return result;
        }
    }
    

    3、创建切面类

    // @Aspect表示这个类是一个切面类
    @Aspect
    // @Component注解保证这个切面类能够放入IOC容器
    @Component
    public class LogAspect {
            
        // @Before注解:声明当前方法是前置通知方法
        // value属性:指定切入点表达式,由切入点表达式控制当前通知方法要作用在哪一个目标方法上
        @Before(value = "execution(public int com.atguigu.aop.api.Calculator.add(int,int))")
        public void printLogBeforeCore() {
            System.out.println("[AOP前置通知] 方法开始了");
        }
        
        @AfterReturning(value = "execution(public int com.atguigu.aop.api.Calculator.add(int,int))")
        public void printLogAfterSuccess() {
            System.out.println("[AOP返回通知] 方法成功返回了");
        }
        
        @AfterThrowing(value = "execution(public int com.atguigu.aop.api.Calculator.add(int,int))")
        public void printLogAfterException() {
            System.out.println("[AOP异常通知] 方法抛异常了");
        }
        
        @After(value = "execution(public int com.atguigu.aop.api.Calculator.add(int,int))")
        public void printLogFinallyEnd() {
            System.out.println("[AOP后置通知] 方法最终结束了");
        }
        
    }
    

    4、测试

    @SpringBootTest
    public class AOPTest {
        
        @Autowired
        private Calculator calculator;
        
        @Test
        public void testAnnotationAOP() {
        
            int add = calculator.add(10, 2);
            System.out.println("方法外部 add = " + add);
        
        }
        
    }
    

    打印效果如下:

    [AOP前置通知] 方法开始了 方法内部 result = 12 [AOP返回通知] 方法成功返回了 [AOP后置通知] 方法最终结束了 方法外部 add = 12

    end