二(8.4)注解和aop

1. AOP 是 Aspect-Oriented Programming,面向切面编程。

它常常和 Java 注解一起使用,尤其在 Spring 里非常常见。可以简单理解为:
注解负责“标记哪里需要增强”,AOP 负责“在这些地方自动插入增强逻辑”。

比如:

@LogExecutionTime
public void createOrder() {
    // 创建订单
}

这个方法本身只关心“创建订单”,而 @LogExecutionTime 表示:这个方法需要记录执行时间。真正记录时间的逻辑,可以交给 AOP 自动处理。

2. AOP 是什么?

AOP 的核心思想是:把一些和业务无关、但很多地方都需要的通用逻辑抽出来,统一处理。
常见场景包括:

日志记录
权限校验
事务管理
接口限流
性能监控
异常处理
缓存处理
审计记录

比如一个订单服务:

public void createOrder() {
    checkPermission();
    startTransaction();

    // 真正的业务逻辑
    saveOrder();

    commitTransaction();
    log();
}

如果每个方法都这样写,业务代码会变得很乱。
AOP 的作用就是让业务方法保持干净:

public void createOrder() {
    saveOrder();
}

而权限、事务、日志这些逻辑由 AOP 在方法执行前后自动加进去。

3. AOP 的几个核心概念

3.1. 切面 Aspect

切面就是一组横切逻辑的集合。
比如“日志切面”“权限切面”“事务切面”。

@Aspect
@Component
public class LogAspect {
}

3.2. 连接点 Join Point

连接点是程序执行过程中的某个点。
在 Spring AOP 里,通常指的是“方法调用”。
比如:

userService.createUser()
orderService.createOrder()

这些方法执行点都可以被 AOP 拦截。

3.3. 切点 Pointcut

切点用来指定:哪些方法需要被拦截。
比如拦截所有 service 包下的方法:

@Pointcut("execution(* com.example.service.*.*(..))") 
public void serviceMethods() {}

也可以拦截带有某个注解的方法:

@Pointcut("@annotation(com.example.annotation.LogExecutionTime)")
public void logExecutionTimeMethods() {}

3.4. 通知 Advice

通知就是“什么时候执行增强逻辑”。
常见通知类型:

@Before        方法执行前
@After         方法执行后,不管是否异常
@AfterReturning 方法正常返回后
@AfterThrowing  方法抛异常后
@Around        包围方法执行,最强大

例如:

@Before("serviceMethods()")
public void before() {
    System.out.println("方法执行前");
}

2. 注解和 AOP 如何配合?

通常分三步。

第一步:定义一个注解

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface LogExecutionTime {
}

解释一下:

@Target(ElementType.METHOD)

表示这个注解只能加在方法上。

@Retention(RetentionPolicy.RUNTIME)

表示这个注解在运行时仍然保留,这样 AOP 才能在运行时识别它。

第二步:在业务方法上使用注解

@Service
public class OrderService {

    @LogExecutionTime
    public void createOrder() {
        System.out.println("创建订单");
    }
}

这时 createOrder() 被标记为“需要记录执行时间”。

第三步:用 AOP 拦截这个注解

@Aspect
@Component
public class LogAspect {

    @Around("@annotation(com.example.annotation.LogExecutionTime)")
    public Object logExecutionTime(ProceedingJoinPoint joinPoint) throws Throwable {
        long start = System.currentTimeMillis();

        Object result = joinPoint.proceed();

        long end = System.currentTimeMillis();

        System.out.println(joinPoint.getSignature().getName()
                + " 执行耗时:" + (end - start) + "ms");

        return result;
    }
}

核心是这一句:

@Around("@annotation(com.example.annotation.LogExecutionTime)")

意思是:拦截所有加了 @LogExecutionTime 注解的方法。
而这一句:

joinPoint.proceed();

表示执行原来的业务方法。
所以执行流程大概是:

调用 createOrder()
        ↓
进入 AOP 切面
        ↓
记录开始时间
        ↓
执行 createOrder() 原始方法
        ↓
记录结束时间
        ↓
打印耗时
        ↓
返回结果

3. 一个更实际的例子:权限校验

定义注解:

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface RequireRole {
    String value();
}

使用注解:

@RequireRole("admin")
public void deleteUser(Long userId) {
    // 删除用户
}

AOP 拦截:

@Around("@annotation(requireRole)")
public Object checkRole(ProceedingJoinPoint joinPoint, RequireRole requireRole) throws Throwable {
    String requiredRole = requireRole.value();

    // 假设这里拿到当前用户角色
    String currentRole = "user";

    if (!requiredRole.equals(currentRole)) {
        throw new RuntimeException("权限不足");
    }

    return joinPoint.proceed();
}

这样业务代码只需要写:

@RequireRole("admin")

不用在每个方法里手动写权限判断。

4. 为什么注解适合配合 AOP?

因为注解本身不做事情,它只是一个“标记”或“配置”。
比如:

@RequireRole("admin")

它只是告诉系统:这个方法需要 admin 权限。

但真正的权限判断逻辑,需要 AOP 去执行。
所以它们的关系可以理解为:

注解:声明意图
AOP:执行逻辑
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值