为什么需要 AOP?

在这里插入图片描述

我们可以通过一个简单的场景演变来回答这个问题。

场景:一个简单的用户服务

假设我们有一个 UserService,它包含几个核心的业务方法:

public class UserServiceImpl implements UserService {
    @Override
    public void addUser(String username) {
        // 核心业务逻辑:向数据库插入一个新用户
        System.out.println("数据库操作:新增用户 " + username);
    }

    @Override
    public void deleteUser(int userId) {
        // 核心业务逻辑:从数据库删除一个用户
        System.out.println("数据库操作:删除用户 " + userId);
    }
}

现在,产品经理提出了几个新需求:

  1. 在每个方法执行前,打印一下方法入参,方便调试。
  2. 记录每个方法执行花费了多长时间。
  3. 在执行数据库操作前,需要检查当前操作员是否有权限。
阶段一:最直观的实现 (没有 AOP)

我们直接在每个方法里添加这些功能代码:

public class UserServiceImpl implements UserService {
    @Override
    public void addUser(String username) {
        // --- 非核心业务代码开始 ---
        System.out.println("[日志] 方法 addUser() 被调用,参数: " + username);
        long startTime = System.currentTimeMillis();
        // 权限检查
        if (!SecurityUtil.hasPermission("addUser")) {
            throw new SecurityException("权限不足!");
        }
        // --- 非核心业务代码结束 ---

        // 核心业务逻辑
        System.out.println("数据库操作:新增用户 " + username);

        // --- 非核心业务代码开始 ---
        long endTime = System.currentTimeMillis();
        System.out.println("[性能] 方法 addUser() 执行耗时: " + (endTime - startTime) + "ms");
        // --- 非核心业务代码结束 ---
    }

    @Override
    public void deleteUser(int userId) {
        // --- 非核心业务代码开始 ---
        System.out.println("[日志] 方法 deleteUser() 被调用,参数: " + userId);
        long startTime = System.currentTimeMillis();
        // 权限检查
        if (!SecurityUtil.hasPermission("deleteUser")) {
            throw new SecurityException("权限不足!");
        }
        // --- 非核心业务代码结束 ---

        // 核心业务逻辑
        System.out.println("数据库操作:删除用户 " + userId);

        // --- 非核心业务代码开始 ---
        long endTime = System.currentTimeMillis();
        System.out.println("[性能] 方法 deleteUser() 执行耗时: " + (endTime - startTime) + "ms");
        // --- 非核心业务代码结束 ---
    }
}

这样做暴露出了几个 致命的痛点

  1. 代码重复 (Code Duplication):日志、性能监控、权限检查的代码在 addUserdeleteUser 方法中几乎完全一样。如果再来一个 updateUser 方法,我们还得再复制粘贴一遍。

  2. 代码分散 (Code Scattering):日志功能相关的代码,分散在系统的各个角落,没有集中管理。如果现在想把日志输出格式从 [日志] 改为 [INFO],你需要修改所有的方法,非常痛苦且容易遗漏。

  3. 核心业务与非核心业务高度耦合 (High Coupling)UserServiceImpl 的主要职责是处理用户相关的业务。但现在,它被迫“关心”日志、性能和安全这些它本不该关心的事情。这严重违反了软件设计的 单一职责原则 (Single Responsibility Principle)

这些与核心业务无关,但又需要在多个地方重复使用的功能(如日志、事务、安全、性能监控),我们称之为 横切关注点 (Cross-Cutting Concerns)


阶段二:AOP 的闪亮登场

AOP (Aspect-Oriented Programming, 面向切面编程) 的诞生就是为了优雅地解决上述问题。

它的核心思想是:将横切关注点与业务主逻辑分离,实现解耦。

AOP 允许我们把这些“横切关注点”的代码逻辑,提取到一个独立的模块中,这个模块我们称之为 “切面” (Aspect)。然后,我们通过配置告诉框架:“请在‘某个地方’(比如 UserService 的所有 public 方法执行前/后)自动应用这个‘切面’里的逻辑。”

使用 AOP 改造后的代码

1. 保持纯净的业务逻辑

UserServiceImpl 回到了它最开始的纯净状态,只关心自己的核心职责。

public class UserServiceImpl implements UserService {
    @Override
    public void addUser(String username) {
        System.out.println("数据库操作:新增用户 " + username);
    }

    @Override
    public void deleteUser(int userId) {
        System.out.println("数据库操作:删除用户 " + userId);
    }
}

这代码看起来多么清爽!

2. 定义一个独立的“切面”

我们创建一个 SystemArchitectureAspect 来统一管理日志、性能和安全。

@Aspect // 声明这是一个切面
@Component
public class SystemArchitectureAspect {

    // 定义一个“切点”,匹配 UserService 的所有 public 方法
    @Pointcut("execution(public * com.example.UserService.*(..))")
    public void userServiceMethods() {}

    // “前置通知”:在目标方法执行前运行
    @Before("userServiceMethods()")
    public void logBefore(JoinPoint joinPoint) {
        System.out.println("[日志] 方法 " + joinPoint.getSignature().getName() + "() 被调用,参数: " + Arrays.toString(joinPoint.getArgs()));
    }

    // “环绕通知”:可以控制目标方法的执行,功能最强大
    @Around("userServiceMethods()")
    public Object profile(ProceedingJoinPoint pjp) throws Throwable {
        // 权限检查
        if (!SecurityUtil.hasPermission(pjp.getSignature().getName())) {
            throw new SecurityException("权限不足!");
        }
        
        long startTime = System.currentTimeMillis();
        Object result = pjp.proceed(); // 调用原始的目标方法
        long endTime = System.currentTimeMillis();
        System.out.println("[性能] 方法 " + pjp.getSignature().getName() + "() 执行耗时: " + (endTime - startTime) + "ms");
        return result;
    }
}

总结:所以,为什么需要 AOP?

AOP 不是一门新的技术,而是一种编程思想,它帮助我们解决了传统面向对象编程 (OOP) 难以处理的“横切关注点”问题。

一句话总结:AOP 让我们能够将散布在应用中多个角落的通用功能(如日志、事务、安全)聚合到一个地方进行统一管理,从而让业务代码更纯粹、系统模块化更清晰、代码可维护性和复用性更高。

它就像给你的程序装上了一个“插件系统”,你可以在不修改任何一行核心业务代码的情况下,动态的为系统添加或移除功能。Spring 框架的声明式事务 (@Transactional) 就是 AOP 最经典的应用。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

冰糖心书房

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值