Spring AOP

AOP:面向切面的编程。

AOP并不是Spring特有的技术,只是Spring框架很好的支持了AOP。

AOP解决了横切关注的问题,所谓的横切关注,就是执行多个不同的方法时,都需要执行相同的代码片段。

例如,当前项目中的数据处理流程为:

登 录:  客户端 ---请求---> Controller ------> Sevice ------> Mapper

添加相册:客户端 ---请求---> Controller ------> Sevice ------> Mapper

修改品牌:客户端 ---请求---> Controller ------> Sevice ------> Mapper

假设,存在需求:统计各Service方法的执行耗时。

要实现以上需求,首先,在项目中添加spring-boot-starter-aop依赖项:

<!-- Spring Boot AOP -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-aop</artifactId>
</dependency>

并编写切面代码:

@Slf4j
@Aspect // 将当前类标记为“切面”类
@Component // 将当前类标记为“组件”类
public class TimerAspect {
public TimerAspect() {
        log.debug("创建切面对象:TimerAspect");
    }

    // 【AOP的核心概念】
    // 连接点(JoinPoint):数据处理过程中的某个节点,可能是调用了方法,或抛出了异常
    // 切入点(PointCut):选择1个或多个连接点的表达式
    // ---------------------------------------------------------
    // 【通知注解】
    // @Before:表示“在……之前”,方法应该是无参数的
    // @After:表示“在……之后”,无论顺利执行结束,还是抛出异常,都会执行,方法应该是无参数的
    // @AfterReturning:表示“在返回结果之后”,方法的参数是JoinPoint和返回值对象
    // @AfterThrowing:表示“在抛出异常之后”,方法的参数是JoinPoint和异常对象
    // @Around:表示“包裹”,也称之“环绕”,使用此注解时,方法的参数必须是ProceedingJoinPoint类型的
    // ---------------------------------------------------------
    // @Around开始
    // try {
    //    @Before
    //    连接点方法
    //    @AfterReturning
    // } catch (Throwable e) {
    //    @AfterThrowing
    // } finally {
    //    @After
    // }
    // @Around结束
    // ---------------------------------------------------------
    // 注解中的execution内部配置表达式,以匹配需要在哪些方法上执行切面代码
    // 在表达式中,星号(*)是通配符,可以匹配1次任意内容
    // 例如,在返回值位置使用星号,表示此方法可以是任意返回值,包括:void / int / String ...
    // 在表达式中,连续的2个小数点(..)也是通配符,可以匹配0~n次任意内容,仅能用于包名和参数列表部分
    // 例如,在方法的参数列表使用2个小数点,表示此方法的参数列表中可以是0个参数,也可以是n个参数
    @Around("execution(* cn.tedu.csmall.product.service.*.*(..))")
    //                 ↑ 此星号表示方法的返回值类型
    //                   ↑----------- 根包 ------------↑
    //                                                  ↑ 类名
    //                                                    ↑ 方法名
    //                                                       ↑↑ 参数列表
    // 提示:在“返回值类型”的左侧,还可以配置修饰符,例如方法的注解等,修饰符是可选的配置
    public Object timer(ProceedingJoinPoint pjp) throws Throwable {
        log.debug("执行了TimerAspect中的方法……");
        log.debug("【{}】类型的对象调用了【{}】方法,传入的参数为【{}】",
                pjp.getTarget().getClass().getName(),
                pjp.getSignature().getName(),
                pjp.getArgs());

        long start = System.currentTimeMillis();

        // 调用ProceedingJoinPoint的proceed()方法,本质就是执行了连接点对应的方法
        // 注意:调用的proceed()方法会抛出Throwable,此时必须抛出,不可以使用try...catch捕获并处理
        // 注意:调用proceed()方法时必须获取返回值,此返回值就是连接点对应的方法的返回值,必须作为当前切面方法的返回值
        Object result = pjp.proceed();

        long end = System.currentTimeMillis();
        log.debug("执行耗时:{}ms", end - start);

        return result;
    }

}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值