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 还有其他疑问,欢迎在评论区交流! 🚀

相关推荐
n8n10 分钟前
Spring AI 三层架构详解:ChatModel → ChatClient → Controller,同步调用 vs 流式调用(SSE)
后端
小傅哥14 分钟前
Java + DDD,1:1 复刻 Deepseek Harness 项目
前端·后端·ai编程
Lambert28116 分钟前
AgentScope Java 从零(03):Agent 的记性默认全开,我在第 50 轮翻了车
后端·aigc
积硅步致千里23 分钟前
Word 里的 .wmf 其实是 EMF:一次 metafile 转 PNG 排障
前端·后端
爱读源码的大都督35 分钟前
DeepSeek面试官问:生产RAG系统回答不准确,该如何定位和优化?这样回答,能让面试官当场给你Offer!
java·后端·python
杨运交1 小时前
[069][公共模块]Spring Boot 全局异常处理与参数校验实战(下):校验异常精细化处理与 WebFlux 适配
java·spring boot·后端
Andya_net1 小时前
Spring Boot | 条件注解完全指南:从 @Conditional 到 @ConditionalOnExpression 的原理、实践与避坑
spring boot·后端·python
ly76892 小时前
Spring 中的 @Configuration 与 @Component 差异:为何代理时机决定 Bean 生命周期行为
java·后端·spring·注解·代理·bean生命周期
明月_清风2 小时前
字符串匹配四大经典算法:BF、RK、BM、KMP 到底有什么区别?
后端·算法
卷无止境2 小时前
测试全绿,功能能跑,代码却烂到没法上线:AI编程助手留下的十个坑
后端·python