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

相关推荐
编程乐趣2 小时前
基于.Net开发的数据库导入导出的开源项目
后端
赵星星5202 小时前
别再搞混了!深入浅出理解Java线程中start()和run()的本质区别
java·后端
Ray662 小时前
FST
后端
白露与泡影2 小时前
SpringBoot 自研运行时 SQL 调用树,3 分钟定位慢 SQL!
spring boot·后端·sql
花花无缺3 小时前
接口(interface)中的常量和 类(class)中的常量的区别
java·后端
舒一笑3 小时前
利用Mybatis自定义排序规则实现复杂排序
后端·排序算法·mybatis
毕设源码-郭学长3 小时前
【开题答辩全过程】以 基于vue+springboot的校园疫情管理系统的设计与实现为例,包含答辩的问题和答案
java·spring boot·后端
Joey_Chen3 小时前
【Golang开发】快速入门Go——Goroutine和Channel
后端·go
CF14年老兵3 小时前
努力生活,本身就是一种成就
前端·后端·trae
LSTM973 小时前
Python与Excel的华丽邂逅:用Spire.XLS for Python高效读取数据
后端