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

291 阅读3分钟

🚀 深入解析 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 动态代理

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

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 动态代理

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

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代理对象工厂,负责创建代理
AdvisedSupportAOP 配置管理,包含目标对象、切面、通知等信息
DefaultAopProxyFactory选择代理方式(JDK 代理或 CGLIB 代理)
JdkDynamicAopProxyJDK 动态代理实现
CglibAopProxyCGLIB 代理实现

3.2 源码解析

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

ProxyFactory proxyFactory = new ProxyFactory(new UserServiceImpl());
proxyFactory.addAdvice(new MyMethodInterceptor());
UserService proxy = (UserService) proxyFactory.getProxy();

底层会判断:

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

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

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

@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 用于声明式事务管理:

@Transactional
public void saveOrder() {
    orderDao.save();
}

日志记录

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

@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;
}

权限校验

在方法执行前检查权限:

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