冬眠的笔记
首页文章分类书单项目关于
冬眠
X

© 2026 冬眠的笔记 · 用文字记录思考,用思考改变生活

首页>文章>Java
JavaSpringAOP动态代理

Spring AOP 实现机制

Spring AOP 的 JDK 动态代理与 CGLIB 实现、织入时机以及常见使用场景

冬眠
冬眠
专注于技术、阅读与思考
2025-11-19
发布日期
7 min read
阅读时长
浏览量
Spring AOP 实现机制

Spring AOP的实现机制主要基于动态代理。当目标对象实现了接口时,Spring AOP使用JDK动态代理来创建代理对象;当目标对象没有实现接口时,Spring AOP使用CGLIB动态代理来创建代理对象。

JDK动态代理

JDK动态代理是Java标准库提供的一种动态代理实现方式。它通过在运行时生成目标对象的代理对象,并实现目标对象所实现的接口来实现代理。在Spring AOP中,JDK动态代理是基于Java反射机制实现的,它能够拦截目标对象方法的调用并在方法执行前后插入通知逻辑。

JDK动态代理是基于接口的代理方式,它要求目标对象必须实现接口。这是因为JDK动态代理是通过生成目标对象的接口的实现类来创建代理对象的。当我们为一个类创建代理对象时,JDK动态代理会在运行时创建一个实现了目标对象接口的代理类,并在代理类中重写接口中的方法来实现代理逻辑。因此,如果一个类没有实现接口,就无法通过JDK动态代理来创建代理对象。

核心类

java.lang.reflect.Proxy

java.lang.reflect.InvocationHandler

Proxy类是JDK动态代理的核心类之一。它提供了创建代理对象的静态方法 newProxyInstance() 用于创建一个实现了指定接口的代理类的实例。

InvocationHandler接口是JDK动态代理的另一个核心部分,它负责处理代理对象的方法调用。当我们调用代理对象的方法时,实际上会调用InvocationHandler的invoke()方法,并将调用的方法名、参数等信息传递给invoke()方法。

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

// 定义一个接口
interface UserService {
    void addUser(String username);
}

// 实现接口的目标类
class UserServiceImpl implements UserService {
    public void addUser(String username) {
        System.out.println("Adding user: " + username);
    }
}

// 实现InvocationHandler接口的代理处理器类
class MyInvocationHandler implements InvocationHandler {
    private Object target; // 目标对象

    public MyInvocationHandler(Object target) {
        this.target = target;
    }

    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("Before method: " + method.getName());
        Object result = method.invoke(target, args); // 调用目标对象的方法
        System.out.println("After method: " + method.getName());
        return result;
    }
}

public class Main {
    public static void main(String[] args) {
        // 创建目标对象实例
        UserService target = new UserServiceImpl();

        // 创建代理处理器实例
        InvocationHandler handler = new MyInvocationHandler(target);

        // 创建代理对象
        UserService proxy = (UserService) Proxy.newProxyInstance(
            target.getClass().getClassLoader(),
            target.getClass().getInterfaces(),
            handler
        );

        // 调用代理对象的方法
        proxy.addUser("Alice");
    }
}

CGLIB动态代理

CGLIB动态代理是基于字节码生成技术实现的一种动态代理方式。它通过继承目标对象并重写其方法来实现代理。在Spring AOP中,当目标对象没有实现接口时,Spring会使用CGLIB动态代理来创建代理对象。与JDK动态代理相比,CGLIB动态代理能够代理没有实现接口的类。

注意:因为是继承目标对象重写其方法来实现代理,所以final类和final方法时无法被代理的。

同理,静态方法和private方法也是无法被代理的。

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;

// 目标类,无需实现接口
class UserService {
    public void addUser(String username) {
        System.out.println("Adding user: " + username);
    }
}

// 实现MethodInterceptor接口的代理拦截器
class MyMethodInterceptor implements MethodInterceptor {
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
        System.out.println("Before method: " + method.getName());
        Object result = proxy.invokeSuper(obj, args); // 调用目标对象的方法
        System.out.println("After method: " + method.getName());
        return result;
    }
}

public class Main {
    public static void main(String[] args) {
        // 创建Enhancer对象
        Enhancer enhancer = new Enhancer();
        // 设置父类(目标类)
        enhancer.setSuperclass(UserService.class);
        // 设置回调对象(代理拦截器)
        enhancer.setCallback(new MyMethodInterceptor());
        // 创建代理对象
        UserService proxy = (UserService) enhancer.create();

        // 调用代理对象的方法
        proxy.addUser("Alice");
    }
}

具体选择

Spring中关于JDK动态代理和CGLIB动态代理的选择是在org.springframework.aop.framework.DefaultAopProxyFactory#createAopProxy 进行判断的。

public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
    if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
        Class<?> targetClass = config.getTargetClass();
        if (targetClass == null) {
            throw new AopConfigException("TargetSource cannot determine target class: " +
                    "Either an interface or a target is required for proxy creation.");
        }
        if (targetClass.isInterface() || Proxy.isProxyClass(targetClass) || ClassUtils.isLambdaClass(targetClass)) {
            return new JdkDynamicAopProxy(config);
        }
        return new ObjenesisCglibAopProxy(config);
    }
    else {
        return new JdkDynamicAopProxy(config);
    }
}

可以看到,Spring中默认使用JDK的动态代理;如果配置了优化选项、强制使用代理类或者没有用户提供的代理接口,则根据目标类是否为接口、是否为JDK代理类、是否为Lambda类来决定使用 JDK 动态代理还是 CGLIB 代理。如果目标类是接口或者 JDK 代理类,则使用 JDK 动态代理;否则,使用 CGLIB 代理。

文章标签

JavaSpringAOP动态代理CGLIB
Spring 扩展点全景
上一篇

Spring 扩展点全景

2025-11-19

Spring Bean 的加载过程
下一篇

Spring Bean 的加载过程

2025-11-19

冬眠

冬眠

博主

专注于技术、阅读与思考。在这里记录学习、思考与生活。

116
文章
2
分类
关注我
系列:SpringBoot 扩展

第 1 篇,共 4 篇

已是第一篇

下一篇

Spring 扩展点全景

文章目录

目录

  • JDK动态代理
  • CGLIB动态代理
  • 具体选择

相关文章

查看更多
PlatformTransactionManager 事务管理器

PlatformTransactionManager 事务管理器

2025-11-19 · 19 min read

Spring 扩展点全景

Spring 扩展点全景

2025-11-19 · 4 min read

Spring Bean 的加载过程

Spring Bean 的加载过程

2025-11-19 · 20 min read