心心念念的AOP

面向切面编程

AOP = 面向切面编程

AOP并不是Spring框架特有的功能,不依赖于Spring也可以实现AOP,只是Spring很好的支持了AOP!

常规的数据处理流程大致是:

注册:前端页面 -----> Controller -----> Service -----> Mapper

登录:前端页面 -----> Controller -----> Service -----> Mapper

改密:前端页面 -----> Controller -----> Service -----> Mapper

假设,需要在处理每种/每次请求时,都需要执行相同的某个任务,例如“统计业务层代码的执行耗时”,在传统的做法中,可以将“统计耗时”的代码封装在某个方法中,然后,在业务层的reg()login()changePassword()中均调用这个“统计耗时”的方法即可!但是,在比较复杂的项目中,涉及的业务可能有成百上千个,就需要在成百上千个业务方法中都添加调用“统计耗时”的方法,不便于统一管理!

面向切面编程,是在数据处理流程中,假设存在某个切面,这个切面可以在任何位置,例如在ControllerService之间,或在ServiceMapper之间,甚至可以同时存在多个切面,每个切面中都可以添加方法,当数据处理流程执行到切面时,就会执行切面中的方法!

在使用面向切面的编程时,只需要确定切面的位置,及切面中需要执行的代码即可,对原有的ControllerService等组件中的代码不需要进行任何调整!

首先,需要添加aspectjtoolsaspectjweaver依赖:(Springboot中居然没有自带这两个依赖? 是否说明AOP并不常用?)

<!-- https://mvnrepository.com/artifact/org.aspectj/aspectjtools -->
<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjtools</artifactId>
    <version>1.9.5</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
    <version>1.9.5</version>
</dependency>

暂定目标为“统计业务层代码的执行耗时”。

cn.tedu.store包下创建aop包,用于存放切面类(当然,也可以使用其它包名,例如aspect),并在这个包中创建TimerAspect类(切面类推荐使用Aspect作为类名的最后一个单词)。作为一个切面类,必须添加@Aspect注解,同时,是由Spring管理的,所以,还需要添加@Component注解:

package cn.tedu.store.aop;

import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class TimerAspect {

}

然后,在切面类中,自定义方法,实现切面中的功能,并通过注解配置切面的位置:

@Around("execution(* cn.tedu.store.service.impl.*.*(..))")
public Object aaaaa(ProceedingJoinPoint pjp) throws Throwable {
    // 记录开始时间
    long start = System.currentTimeMillis();

    // 执行业务方法,例如注册业务、登录业务等
    Object obj = pjp.proceed();

    // 记录结束时间
    long end = System.currentTimeMillis();
    System.err.println("执行耗时:" + (end - start) + "毫秒。");

    // 返回
    return obj;
}

以上代码中,注解的配置值execution(* cn.tedu.store.service.impl.*.*(..))将确定切面的位置,这段值表示“在cn.tedu.store.service.impl包下的所有类(包名右侧的第1个星号)的所有方法(包名右侧的第2个星号),且无视方法的参数数量(括号中的2个小数)和方法的返回值类型(包名左侧的星号)”,也就是当前项目中所有的业务方法都会匹配上!

以上代码中,使用的@Around注解表示切面的连接方法,@Around表示“包裹”,也就是在应用切面的业务方法之前和之后都存在!也可以使用@Before表示“之前”,则切面在某位置之前,也可以使用@After表示“之后”。

以上代码中,自定义的方法必须添加ProceedingJoinPoint接口类型的参数,该参数的proceed()方法就相当于切面所包裹的位置(业务)需要执行方法,所以,可以通过pjp.proceed()表示“注册业务”,也可以表示“登录业务”或任何其它业务!

需要注意的是:该方法将抛出异常,用于表示具体的业务方法可能抛出的异常,例如“注册”时抛出的UsernameDuplicateException,在切面中,必须将该异常抛出,否则,就必须使用try...catch进行捕获,相当于自行处理了异常,后续控制器类就不会发现这个异常了!另外,调用pjp.proceed()方法将得到一个Object类型的返回值,这个返回值就相当于业务方法的返回值,例如“登录”成功后将返回一个User对象,加载收货地址列表时将返回一个List<Address>,在自定义切面方法时,必须获取该返回值,并且作为切面方法的返回值,否则,就相当于业务方法返回了null

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值