03-深入解析 Spring AOP 原理及源码

🚀 深入解析 Spring AOP 原理及源码

Spring AOP(Aspect-Oriented Programming,面向切面编程)是 Spring 框架的重要特性之一,它允许在不修改源代码的情况下,为方法添加增强功能,如日志记录、事务管理等。

本篇博客将从 AOP 的基本概念 入手,深入 底层原理源码实现,带你彻底搞懂 Spring AOP。


🎯 1. 什么是 AOP?

AOP 主要用于 解耦业务逻辑通用功能(如日志、事务、权限校验),它的核心思想是:

  • 通过 切面(Aspect)横切关注点(Cross-cutting concerns) 与主业务逻辑解耦。
  • 方法执行的不同阶段(如执行前、执行后、异常时) 动态插入代码。

📌 1.1 Spring AOP 的基本概念

术语 解释
切面(Aspect) 封装多个通知的类,定义增强逻辑
通知(Advice) 定义在切入点执行的具体操作(前置、后置、异常等)
切入点(Pointcut) 定义拦截哪些方法
连接点(JoinPoint) 被拦截的方法(符合切入点规则的方法)
代理(Proxy) 通过 JDK 动态代理或 CGLIB 代理生成的增强对象
目标对象(Target) 被代理的原始对象

🔥 2. Spring AOP 的实现方式

Spring AOP 主要使用 动态代理 来实现,支持以下两种方式:

  1. JDK 动态代理 (基于 java.lang.reflect.Proxy,只能代理接口)
  2. CGLIB 动态代理 (基于 net.sf.cglib,代理具体类)

2.1 JDK 动态代理

适用于:目标类实现了接口

java 复制代码
public interface UserService {
    void register(String username);
}

public class UserServiceImpl implements UserService {
    @Override
    public void register(String username) {
        System.out.println(username + " 注册成功!");
    }
}

// 创建代理
UserService proxy = (UserService) Proxy.newProxyInstance(
    UserServiceImpl.class.getClassLoader(),
    new Class[]{UserService.class},
    (proxyObj, method, args) -> {
        System.out.println("方法执行前的增强");
        Object result = method.invoke(new UserServiceImpl(), args);
        System.out.println("方法执行后的增强");
        return result;
    }
);
proxy.register("张三");

2.2 CGLIB 动态代理

适用于:目标类没有实现接口

java 复制代码
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(UserServiceImpl.class);
enhancer.setCallback((MethodInterceptor) (obj, method, args, proxy) -> {
    System.out.println("方法执行前的增强");
    Object result = proxy.invokeSuper(obj, args);
    System.out.println("方法执行后的增强");
    return result;
});
UserServiceImpl proxy = (UserServiceImpl) enhancer.create();
proxy.register("张三");

⚙️ 3. Spring AOP 的核心源码解析

Spring AOP 的核心实现依赖 ProxyFactory,具体流程如下:

  1. 获取目标对象(Target)
  2. 解析切面和通知(Advice)
  3. 生成代理对象(JDK 代理或 CGLIB 代理)
  4. 执行代理方法,触发增强逻辑

3.1 关键类分析

类名 作用
ProxyFactory 代理对象工厂,负责创建代理
AdvisedSupport AOP 配置管理,包含目标对象、切面、通知等信息
DefaultAopProxyFactory 选择代理方式(JDK 代理或 CGLIB 代理)
JdkDynamicAopProxy JDK 动态代理实现
CglibAopProxy CGLIB 代理实现

3.2 源码解析

当一个类被 AOP 代理时,Spring 会通过 ProxyFactory 创建代理:

java 复制代码
ProxyFactory proxyFactory = new ProxyFactory(new UserServiceImpl());
proxyFactory.addAdvice(new MyMethodInterceptor());
UserService proxy = (UserService) proxyFactory.getProxy();

底层会判断:

  • 如果目标类有接口 → 使用 JdkDynamicAopProxy
  • 如果目标类没有接口 → 使用 CglibAopProxy

🚀 4. 如何自定义 AOP 切面?

Spring AOP 提供了 @Aspect 注解来定义切面:

java 复制代码
@Aspect
@Component
public class LogAspect {
    @Before("execution(* com.example.service.*.*(..))")
    public void beforeMethod(JoinPoint joinPoint) {
        System.out.println("执行前:" + joinPoint.getSignature());
    }

    @AfterReturning("execution(* com.example.service.*.*(..))")
    public void afterMethod() {
        System.out.println("执行后");
    }
}

🔍 5. AOP 在实际项目中的应用

事务管理

Spring AOP 用于声明式事务管理:

java 复制代码
@Transactional
public void saveOrder() {
    orderDao.save();
}

日志记录

在方法执行前后记录日志:

java 复制代码
@Around("execution(* com.example..*(..))")
public Object log(ProceedingJoinPoint joinPoint) throws Throwable {
    System.out.println("方法开始:" + joinPoint.getSignature());
    Object result = joinPoint.proceed();
    System.out.println("方法结束");
    return result;
}

权限校验

在方法执行前检查权限:

java 复制代码
@Before("execution(* com.example.service.*.*(..))")
public void checkPermission() {
    if (!UserContext.hasPermission()) {
        throw new RuntimeException("无权限访问");
    }
}

📚 总结

  1. Spring AOP 通过动态代理(JDK 代理或 CGLIB 代理)实现方法增强。
  2. 底层主要依赖 ProxyFactory,根据目标类是否有接口选择 JDK 代理或 CGLIB 代理。
  3. Spring AOP 常用于事务管理、日志记录、权限校验等场景。
  4. 自定义 AOP 需要使用 @Aspect@Around@Before@AfterReturning 等注解。

Spring AOP 是 Spring 核心组件之一,理解其底层原理,有助于在实际项目中更灵活地使用切面编程,提高代码的可维护性和扩展性。


如果你对 Spring AOP 还有其他疑问,欢迎在评论区交流! 🚀

相关推荐
用户23452670098212 小时前
Python构建AI Agent自主智能体系统深度好文
后端·程序员
feathered-feathered12 小时前
Redis基础知识+RDB+AOF(面试)
java·数据库·redis·分布式·后端·中间件·面试
周杰伦_Jay12 小时前
【Eino框架】Go语言驱动的LLM应用开发新范式
开发语言·后端·golang
兔丝12 小时前
Redis + ThinkPHP 实战学习手册(含秒杀场景)
后端
代码or搬砖12 小时前
Spring Cache讲解
java·后端·spring
Json_13 小时前
springboot框架 线程池使用与配置,简单粗暴直接用,再也不用自己创建线程了~
java·spring boot·后端
sin6013 小时前
学习笔记:Mybatis 示例代码,应用场景,面试题
后端
前端小张同学13 小时前
餐饮小程序需要你们
java·前端·后端
王中阳Go13 小时前
都2026年了,PHP还纠结转Go还是Java呢?安利一个无缝迁移的框架~
java·后端·go
老华带你飞13 小时前
二手商城|基于springboot 二手商城系统(源码+数据库+文档)
java·数据库·vue.js·spring boot·后端·spring