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

相关推荐
豌豆花下猫5 分钟前
Python 3.14 t-string 要来了,它与 f-string 有何不同?
后端·python·ai
小奏技术10 分钟前
Spring7将正式弃用Junit 4,我们也是时候迁移到Junit5了
后端
吴佳浩23 分钟前
Python入门指南(四)-项目初始化
人工智能·后端·python
一颗知足的心32 分钟前
Go语言之路————指针、结构体、方法
开发语言·后端·golang
Rabbb2 小时前
C# JSON属性排序、比较 Newtonsoft.Json
后端
蓝易云2 小时前
在Linux、CentOS7中设置shell脚本开机自启动服务
前端·后端·centos
一千柯橘2 小时前
Nestjs 解决 request entity too large
javascript·后端
userkang3 小时前
消失的前后端,崛起的智能体
前端·人工智能·后端·ai·硬件工程
慧一居士3 小时前
Kafka HA集群配置搭建与SpringBoot使用示例总结
spring boot·后端·kafka
@_猿来如此3 小时前
Django 实现电影推荐系统:从搭建到功能完善(附源码)
数据库·后端·python·django