动态代理深度解析:JDK与CGLIB底层实现与实战

动态代理深度解析:JDK与CGLIB底层实现与实战

文章标签: #java #动态代理 #jdk-proxy #cglib #aop #字节码 #反射 #面试

目录


引言:动态代理的技术本质

动态代理(Dynamic Proxy)不是简单的"设计模式应用",而是Java运行时字节码工程 的核心技术。它是Spring AOP、MyBatis Mapper接口、Dubbo RPC、Hibernate延迟加载等主流框架的底层基础设施

核心认知

复制代码
动态代理的技术本质:

┌─────────────────────────────────────────┐
│           编译时静态结构                  │
│  目标类 ←── 编译 ──→ 目标字节码            │
│     ↑                                   │
│     └────── 代理类(编译时未知)            │
│              ↓                          │
│         运行时动态生成                    │
│  代理字节码 ←── ProxyGenerator/ASM ──→ 代理类  │
│     ↑                                   │
│     └────── ClassLoader.defineClass()   │
└─────────────────────────────────────────┘

关键洞察:代理类在源码中不存在,在运行时通过字节码技术"凭空创造"

理解动态代理需要掌握三个核心问题:

  1. 代理类是如何生成的? ------ 字节码生成技术(ProxyGenerator / ASM)
  2. 方法调用是如何被拦截的? ------ 调用转发机制(InvocationHandler / MethodInterceptor)
  3. 调用目标方法时的性能损耗在哪? ------ 反射调用 vs FastClass索引调用

为什么需要动态代理?

复制代码
软件开发中的横切关注点(Cross-cutting Concerns):

业务代码:              代理增强后:
┌──────────┐          ┌──────────────┐
│  核心业务   │          │   日志记录     │
│  订单创建   │    →    │   权限校验     │
│  用户查询   │          │   核心业务     │
│  支付处理   │          │   事务管理     │
└──────────┘          │   性能监控     │
                      └──────────────┘

核心价值:不修改目标类源码,动态织入横切逻辑

理论基础:代理模式的分类与演进

1. 代理模式的本质

代理模式(Proxy Pattern)是结构型设计模式 。核心思想:为其他对象提供一种代理以控制对这个对象的访问

复制代码
代理模式的UML结构:

┌──────────────┐         ┌──────────────┐
│   Subject    │◄────────│  RealSubject │
│  (目标接口)   │         │   (目标实现)  │
└──────┬───────┘         └──────────────┘
       ▲
       │
┌──────┴───────┐
│     Proxy    │
│   (代理类)    │
│              │
│ - realSubject│
│ + request()  │───► preProcess()
│              │     realSubject.request()
│              │     postProcess()
└──────────────┘

2. 代理模式的演进路线

复制代码
代理模式演进时间线:

阶段1:静态代理(编译时确定)
├─ 手动编写代理类
├─ 优点:简单直观
└─ 缺点:每个目标类都需要一个代理类,代码冗余

阶段2:JDK动态代理(运行时生成接口实现)
├─ 基于接口
├─ 使用反射调用
└─ 适用:目标类实现了接口

阶段3:CGLIB动态代理(运行时生成子类)
├─ 基于继承
├─ FastClass索引调用
└─ 适用:目标类无接口

阶段4:字节码织入(编译期/加载期增强)
├─ AspectJ编译时织入
├─ Instrumentation加载时织入
└─ 适用:追求极致性能,无代理开销

3. 静态代理示例

java 复制代码
// 目标接口
public interface UserService {
    void saveUser(String name);
}

// 目标实现
public class UserServiceImpl implements UserService {
    @Override
    public void saveUser(String name) {
        System.out.println("保存用户: " + name);
    }
}

// 静态代理类(编译时手写)
public class UserServiceProxy implements UserService {
    private final UserService target;
    
    public UserServiceProxy(UserService target) {
        this.target = target;
    }
    
    @Override
    public void saveUser(String name) {
        System.out.println("[日志] 开始保存用户: " + name);
        long start = System.currentTimeMillis();
        
        target.saveUser(name);  // 调用目标方法
        
        long cost = System.currentTimeMillis() - start;
        System.out.println("[日志] 保存完成,耗时: " + cost + "ms");
    }
}

静态代理的致命缺陷

  • 每个接口都需要手写代理类
  • 接口方法变更时,代理类必须同步修改
  • 无法复用,维护成本高

底层原理:JVM层面的字节码生成与加载机制

1. JVM类加载机制回顾

复制代码
类加载器的双亲委派模型:

      ┌─────────────────┐
      │   Bootstrap     │  ← 加载核心类(rt.jar)
      │   ClassLoader   │
      └────────┬────────┘
               │ 委派
      ┌────────▼────────┐
      │   Extension     │  ← 加载扩展类(ext/目录)
      │   ClassLoader   │
      └────────┬────────┘
               │ 委派
      ┌────────▼────────┐
      │   Application   │  ← 加载用户类(classpath)
      │   ClassLoader   │
      └────────┬────────┘
               │ 委派
      ┌────────▼────────┐
      │    Custom       │  ← 自定义类加载器
      │   ClassLoader   │
      └─────────────────┘

动态代理的特殊性:
代理类需要实现用户接口,但接口由AppClassLoader加载
代理类由defineClass0()定义,需要与接口类加载器兼容

2. JDK动态代理的字节码生成原理

JDK动态代理通过sun.misc.ProxyGenerator生成字节码:

复制代码
字节码生成流程:

Proxy.newProxyInstance()
        │
        ▼
getProxyClass0(loader, interfaces)
        │
        ▼
ProxyClassFactory.apply()
        │
        ├── 1. 生成代理类名:com.sun.proxy.$Proxy0
        ├── 2. ProxyGenerator.generateProxyClass()
        │      │
        │      ├── 生成类头(ACC_PUBLIC | ACC_FINAL)
        │      ├── 生成字段:private static Method m0, m1, m2...
        │      ├── 生成静态代码块:初始化Method对象
        │      ├── 生成构造器:public $Proxy0(InvocationHandler)
        │      └── 生成方法体:super.h.invoke(this, mX, args)
        │
        └── 3. Unsafe.defineClass0() 加载到JVM

生成的$Proxy0类结构:

public final class $Proxy0 extends Proxy implements UserService {
    private static Method m1;  // equals方法
    private static Method m2;  // hashCode方法
    private static Method m3;  // UserService.saveUser方法
    
    static {
        try {
            m1 = Class.forName("java.lang.Object").getMethod("equals", 
                Class.forName("java.lang.Object"));
            m2 = Class.forName("java.lang.Object").getMethod("hashCode");
            m3 = Class.forName("UserService").getMethod("saveUser", 
                Class.forName("java.lang.String"));
        } catch (NoSuchMethodException e) {
            throw new NoSuchMethodError(e.getMessage());
        }
    }
    
    public $Proxy0(InvocationHandler h) {
        super(h);
    }
    
    public final void saveUser(String name) {
        try {
            super.h.invoke(this, m3, new Object[]{name});
        } catch (Error | RuntimeException e) {
            throw e;
        } catch (Throwable e) {
            throw new UndeclaredThrowableException(e);
        }
    }
    
    public final boolean equals(Object obj) {
        try {
            return (Boolean) super.h.invoke(this, m1, new Object[]{obj});
        } catch (...) { ... }
    }
    
    // hashCode()、toString() 类似...
}

关键机制

  • 所有方法都转发到 InvocationHandler.invoke()
  • 方法对象(Method)在静态代码块中初始化,避免每次调用反射查找
  • 代理类被声明为 final,防止被进一步继承

3. CGLIB的字节码生成原理

CGLIB(Code Generation Library)基于ASM框架直接操作字节码:

复制代码
CGLIB字节码生成架构:

┌─────────────────────────────────────┐
│           Enhancer                  │
│  - setSuperclass()                  │
│  - setCallback()                    │
│  - create() ──────┐                 │
└───────────────────┼─────────────────┘
                    │
                    ▼
┌─────────────────────────────────────┐
│      AbstractClassGenerator         │
│  - generate()                       │
│  - 缓存策略(key → Class)           │
└─────────────┬───────────────────────┘
              │
              ▼
┌─────────────────────────────────────┐
│      DefaultGeneratorStrategy       │
│  - generate()                       │
│  - 调用 ASM ClassWriter             │
└─────────────┬───────────────────────┘
              │
              ▼
┌─────────────────────────────────────┐
│      ASM ClassVisitor               │
│  - visit()          → 类声明        │
│  - visitMethod()    → 方法生成      │
│  - visitField()     → 字段生成      │
│  - visitEnd()       → 完成写入      │
└─────────────────────────────────────┘

生成两个类:
1. OrderService$$EnhancerByCGLIB:代理类(继承目标类)
2. OrderService$$FastClassByCGLIB:FastClass索引类

CGLIB生成的代理类结构

java 复制代码
public class OrderService$$EnhancerByCGLIB extends OrderService 
    implements Factory {
    
    // 回调对象(MethodInterceptor)
    private MethodInterceptor CGLIB$CALLBACK_0;
    
    // 每个被代理方法对应一个MethodProxy和索引
    private static final MethodProxy CGLIB$createOrder$0$Proxy;
    private static final int CGLIB$createOrder$0$Index;
    
    // 原始方法的Method对象
    private static final Method CGLIB$createOrder$0$Method;
    
    static {
        CGLIB$createOrder$0$Method = 
            ReflectUtils.findMethod("OrderService", "createOrder", "Order");
        CGLIB$createOrder$0$Proxy = 
            MethodProxy.create(
                cls1,           // OrderService.class
                cls2,           // OrderService$$EnhancerByCGLIB.class
                "(Order)V",     // 方法签名
                "createOrder",  // 父类方法名
                "CGLIB$createOrder$0" // 代理类方法名
            );
        CGLIB$createOrder$0$Index = 12; // FastClass索引
    }
    
    // 被代理的方法
    public final void createOrder(Order order) {
        MethodInterceptor tmp = CGLIB$CALLBACK_0;
        if (tmp == null) {
            CGLIB$BIND_CALLBACKS(this);
            tmp = CGLIB$CALLBACK_0;
        }
        
        if (tmp != null) {
            // 调用拦截器
            tmp.intercept(
                this,                       // obj
                CGLIB$createOrder$0$Method, // method
                new Object[]{order},        // args
                CGLIB$createOrder$0$Proxy   // MethodProxy
            );
        } else {
            super.createOrder(order);
        }
    }
    
    // 原始方法代理(用于invokeSuper)
    final void CGLIB$createOrder$0(Order order) {
        super.createOrder(order);
    }
}

CGLIB生成的FastClass结构

java 复制代码
public class OrderService$$FastClassByCGLIB extends FastClass {
    
    // 构造器:接收目标类Class对象
    public OrderService$$FastClassByCGLIB(Class clazz) {
        super(clazz);
    }
    
    // 根据方法名和参数类型获取索引
    public int getIndex(String name, Class[] params) {
        switch(name.hashCode()) {
            case -1182772644: // "createOrder".hashCode()
                if (params.length == 1 && params[0] == Order.class) {
                    return 12; // createOrder对应索引12
                }
                break;
            // ... 其他方法
        }
        return -1;
    }
    
    // 根据索引直接调用方法,无需反射
    public Object invoke(int index, Object target, Object[] args) {
        OrderService obj = (OrderService) target;
        switch (index) {
            case 12: 
                obj.createOrder((Order) args[0]);
                return null;
            case 13:
                obj.queryOrder((String) args[0]);
                return null;
            // ...
            default:
                throw new IllegalArgumentException("Cannot find matching method");
        }
    }
    
    // 根据方法签名获取索引(用于MethodProxy)
    public int getIndex(Class[] params) {
        // 构造器索引
    }
    
    // 根据索引创建实例
    public Object newInstance(int index, Object[] args) {
        switch(index) {
            case 0: return new OrderService();
            // ...
        }
    }
}

FastClass机制的核心价值

复制代码
方法调用方式对比:

方式1:反射调用(JDK动态代理)
Method.invoke(target, args)
  ├── 检查方法可见性
  ├── 参数类型转换
  ├── 调用Native方法(JNI)
  └── 无法被JVM内联优化

方式2:FastClass索引调用(CGLIB)
FastClass.invoke(index, target, args)
  ├── switch(index) 直接跳转
  ├── 强转参数类型
  └── 直接调用目标方法
  
性能差异:
- 反射调用:~15-20x 直接调用
- FastClass:~1.2-2x 直接调用(接近原生)

4. 内存模型与元空间占用

复制代码
动态代理的内存模型:

┌─────────────────────────────────────────┐
│              元空间(Metaspace)           │
│  ┌─────────────────────────────────┐    │
│  │  JDK代理类:com.sun.proxy.$Proxy0 │    │
│  │  - 类结构信息                      │    │
│  │  - 静态字段(Method对象)           │    │
│  │  - 方法字节码                      │    │
│  └─────────────────────────────────┘    │
│  ┌─────────────────────────────────┐    │
│  │  CGLIB代理类:*$$EnhancerByCGLIB  │    │
│  │  - 类结构信息                      │    │
│  │  - 静态字段(MethodProxy)         │    │
│  │  - 方法字节码                      │    │
│  └─────────────────────────────────┘    │
│  ┌─────────────────────────────────┐    │
│  │  CGLIB FastClass:*$$FastClassByCGLIB│ │
│  │  - getIndex() 方法                │    │
│  │  - invoke() 方法(switch表)       │    │
│  └─────────────────────────────────┘    │
└─────────────────────────────────────────┘

内存占用估算(单个代理类):
- JDK代理:~2-5KB(取决于接口方法数量)
- CGLIB代理:~5-15KB(代理类 + FastClass)
- 大量代理类时需注意元空间OOM(-XX:MaxMetaspaceSize)

源码深度分析:JDK动态代理核心源码逐行解读

1. Proxy.newProxyInstance() 完整源码

java 复制代码
// java.lang.reflect.Proxy

/**
 * 创建代理实例的核心方法
 * 
 * @param loader     定义代理类的类加载器
 * @param interfaces 代理类要实现的接口列表
 * @param h          调用处理器(InvocationHandler)
 * @return 代理对象
 */
public static Object newProxyInstance(ClassLoader loader,
                                      Class<?>[] interfaces,
                                      InvocationHandler h) {
    // 【第1步】参数校验:InvocationHandler不能为null
    Objects.requireNonNull(h);
    
    // 【第2步】克隆接口数组,防止外部修改影响缓存key
    // 这是防御性编程,确保后续使用的接口数组不可变
    final Class<?>[] intfs = interfaces.clone();
    
    // 【第3步】SecurityManager安全检查
    // 检查当前调用者是否有权限创建代理类
    final SecurityManager sm = System.getSecurityManager();
    if (sm != null) {
        checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
    }
    
    // 【第4步】生成或获取代理类(核心中的核心)
    // 此处有缓存机制:如果该接口组合已生成过代理类,直接返回缓存
    Class<?> cl = getProxyClass0(loader, intfs);
    
    // 【第5步】通过反射创建代理实例
    try {
        if (sm != null) {
            checkNewProxyPermission(Reflection.getCallerClass(), cl);
        }
        
        // 获取构造器:public $Proxy0(InvocationHandler h)
        final Constructor<?> cons = cl.getConstructor(constructorParams);
        final InvocationHandler ih = h;
        
        // 如果构造器不可访问(非public),尝试取消访问检查
        if (!Modifier.isPublic(cl.getModifiers())) {
            AccessController.doPrivileged(new PrivilegedAction<Void>() {
                public Void run() {
                    cons.setAccessible(true);
                    return null;
                }
            });
        }
        
        // 创建实例:new $Proxy0(h)
        return cons.newInstance(new Object[]{h});
        
    } catch (IllegalAccessException | InstantiationException e) {
        throw new InternalError(e.toString(), e);
    } catch (InvocationTargetException e) {
        Throwable t = e.getCause();
        if (t instanceof RuntimeException) {
            throw (RuntimeException) t;
        } else {
            throw new InternalError(t.toString(), t);
        }
    } catch (NoSuchMethodException e) {
        throw new InternalError(e.toString(), e);
    }
}

2. getProxyClass0() 与缓存机制

java 复制代码
// Proxy.java

private static Class<?> getProxyClass0(ClassLoader loader, 
                                       Class<?>... interfaces) {
    // 限制接口数量:最多65535个(JVM规范限制)
    if (interfaces.length > 65535) {
        throw new IllegalArgumentException("interface limit exceeded");
    }
    
    // 【关键】从缓存获取或生成代理类
    // proxyClassCache是WeakCache<ClassLoader, Class<?>[], Class<?>>
    return proxyClassCache.get(loader, interfaces);
}

// WeakCache的get方法(简化版)
public V get(K key, P parameter) {
    // key: ClassLoader
    // parameter: Class<?>[](接口数组)
    
    Objects.requireNonNull(parameter);
    
    // 清理已被GC的引用
    expungeStaleEntries();
    
    // 构建缓存key(ClassLoader的弱引用)
    Object cacheKey = CacheKey.valueOf(key, refQueue);
    
    // 获取或创建该ClassLoader对应的ConcurrentMap
    ConcurrentMap<Object, Supplier<V>> valuesMap = map.get(cacheKey);
    if (valuesMap == null) {
        ConcurrentMap<Object, Supplier<V>> oldValuesMap
            = map.putIfAbsent(cacheKey,
                valuesMap = new ConcurrentHashMap<>());
        if (oldValuesMap != null) {
            valuesMap = oldValuesMap;
        }
    }
    
    // 构建子key(基于接口数组的WeakReference)
    Object subKey = Objects.requireNonNull(subKeyFactory.apply(key, parameter));
    
    // 获取或创建Supplier(Factory或CacheValue)
    Supplier<V> supplier = valuesMap.get(subKey);
    Factory factory = null;
    
    while (true) {
        if (supplier != null) {
            // 获取值(Factory.get()或CacheValue.get())
            V value = supplier.get();
            if (value != null) {
                return value;
            }
        }
        
        // 首次访问,创建Factory
        if (factory == null) {
            factory = new Factory(key, parameter, subKey, valuesMap);
        }
        
        if (supplier == null) {
            supplier = valuesMap.putIfAbsent(subKey, factory);
            if (supplier == null) {
                supplier = factory;
            }
        } else {
            // 替换无效的supplier
            if (valuesMap.replace(subKey, supplier, factory)) {
                supplier = factory;
            } else {
                supplier = valuesMap.get(subKey);
            }
        }
    }
}

缓存策略解析

复制代码
WeakCache结构:

Map<ClassLoader, Map<Key, Class<?>>> proxyClassCache

┌─────────────────────────────────────────────────┐
│  ClassLoader_1 ──► ┌─────────────────────────┐  │
│                    │  Key{[I1,I2]} ──► $Proxy0 │  │
│                    │  Key{[I1]}    ──► $Proxy1 │  │
│                    └─────────────────────────┘  │
│  ClassLoader_2 ──► ┌─────────────────────────┐  │
│                    │  Key{[I2,I3]} ──► $Proxy2 │  │
│                    └─────────────────────────┘  │
└─────────────────────────────────────────────────┘

设计要点:
1. 使用WeakReference包装ClassLoader,避免内存泄漏
2. 接口数组也使用WeakReference
3. 代理类使用WeakReference,当ClassLoader被回收时,
   代理类也可被GC回收

3. ProxyClassFactory.apply() 源码

java 复制代码
// Proxy.java 中的内部类

private static final class ProxyClassFactory 
    implements BiFunction<ClassLoader, Class<?>[], Class<?>> {
    
    // 代理类名前缀
    private static final String proxyClassNamePrefix = "$Proxy";
    
    // 原子计数器,用于生成唯一类名
    private static final AtomicLong nextUniqueNumber = new AtomicLong();
    
    @Override
    public Class<?> apply(ClassLoader loader, Class<?>[] interfaces) {
        
        // 【1】验证所有接口(非空、是接口、类加载器一致)
        Map<Class<?>, Boolean> interfaceSet = new IdentityHashMap<>(interfaces.length);
        for (Class<?> intf : interfaces) {
            // 验证接口是否由指定的类加载器加载
            Class<?> interfaceClass = null;
            try {
                interfaceClass = Class.forName(intf.getName(), false, loader);
            } catch (ClassNotFoundException e) {
            }
            if (interfaceClass != intf) {
                throw new IllegalArgumentException(
                    intf + " is not visible from class loader");
            }
            
            // 验证是否是接口
            if (!interfaceClass.isInterface()) {
                throw new IllegalArgumentException(
                    interfaceClass.getName() + " is not an interface");
            }
            
            // 验证接口唯一性
            if (interfaceSet.put(interfaceClass, Boolean.TRUE) != null) {
                throw new IllegalArgumentException(
                    "repeated interface: " + interfaceClass.getName());
            }
        }
        
        // 【2】确定代理类的包名
        // 规则:如果所有接口都是public,使用com.sun.proxy包
        //       如果有非public接口,使用该接口的包名
        String proxyPkg = null;
        int accessFlags = Modifier.PUBLIC | Modifier.FINAL;
        
        for (Class<?> intf : interfaces) {
            int flags = intf.getModifiers();
            if (!Modifier.isPublic(flags)) {
                accessFlags = Modifier.FINAL;
                String name = intf.getName();
                int n = name.lastIndexOf('.');
                String pkg = ((n == -1) ? "" : name.substring(0, n + 1));
                if (proxyPkg == null) {
                    proxyPkg = pkg;
                } else if (!pkg.equals(proxyPkg)) {
                    throw new IllegalArgumentException(
                        "non-public interfaces from different packages");
                }
            }
        }
        
        if (proxyPkg == null) {
            proxyPkg = ReflectUtil.PROXY_PACKAGE + "."; // "com.sun.proxy."
        }
        
        // 【3】生成唯一类名
        long num = nextUniqueNumber.getAndIncrement();
        String proxyName = proxyPkg + proxyClassNamePrefix + num;
        
        // 【4】生成字节码(核心)
        byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
            proxyName, interfaces, accessFlags);
        
        // 【5】通过Unsafe.defineClass加载类
        try {
            return defineClass0(loader, proxyName,
                                proxyClassFile, 0, proxyClassFile.length);
        } catch (ClassFormatError e) {
            throw new IllegalArgumentException(e.toString());
        }
    }
}

4. ProxyGenerator.generateProxyClass() 源码

java 复制代码
// sun.misc.ProxyGenerator

public static byte[] generateProxyClass(final String name,
                                        Class<?>[] interfaces,
                                        int accessFlags) {
    ProxyGenerator gen = new ProxyGenerator(name, interfaces, accessFlags);
    
    // 生成字节码文件
    final byte[] classFile = gen.generateClassFile();
    
    // 如果设置了系统属性,保存生成的.class文件到磁盘
    // -Dsun.misc.ProxyGenerator.saveGeneratedFiles=true
    if (saveGeneratedFiles) {
        java.security.AccessController.doPrivileged(
            new java.security.PrivilegedAction<Void>() {
                public Void run() {
                    try {
                        int i = name.lastIndexOf('.');
                        Path path;
                        if (i > 0) {
                            Path dir = Paths.get(name.substring(0, i).replace('.', '/'));
                            Files.createDirectories(dir);
                            path = dir.resolve(name.substring(i+1, name.length()) 
                                + ".class");
                        } else {
                            path = Paths.get(name + ".class");
                        }
                        Files.write(path, classFile);
                        return null;
                    } catch (IOException e) {
                        throw new InternalError(
                            "I/O exception saving generated file: " + e);
                    }
                }
            });
    }
    
    return classFile;
}

// 生成类文件的核心方法
private byte[] generateClassFile() {
    // 【1】添加方法:hashCode, equals, toString
    addProxyMethod(hashCodeMethod, Object.class);
    addProxyMethod(equalsMethod, Object.class);
    addProxyMethod(toStringMethod, Object.class);
    
    // 【2】添加接口方法
    for (Class<?> intf : interfaces) {
        for (Method m : intf.getMethods()) {
            addProxyMethod(m, intf);
        }
    }
    
    // 【3】验证方法签名一致性(返回类型)
    for (List<ProxyMethod> sigmethods : proxyMethods.values()) {
        checkReturnTypes(sigmethods);
    }
    
    // 【4】开始生成字节码
    try {
        // 生成字段:private static Method m0, m1, m2...
        methods.add(generateConstructor());
        
        // 生成静态代码块:初始化Method对象
        for (List<ProxyMethod> sigmethods : proxyMethods.values()) {
            for (ProxyMethod pm : sigmethods) {
                fields.add(new FieldInfo(pm.methodFieldName,
                    "Ljava/lang/reflect/Method;",
                    ACC_PRIVATE | ACC_STATIC));
                methods.add(pm.generateMethod());
            }
        }
        
        methods.add(generateStaticInitializer());
        
    } catch (IOException e) {
        throw new InternalError("unexpected I/O Exception", e);
    }
    
    // 【5】确保常量池大小在范围内
    if (cp.getSize() > 65535) {
        throw new IllegalArgumentException("constant pool size limit exceeded");
    }
    
    // 【6】写入类文件结构
    ByteArrayOutputStream bout = new ByteArrayOutputStream();
    DataOutputStream dout = new DataOutputStream(bout);
    
    try {
        // 魔数
        dout.writeInt(0xCAFEBABE);
        // 次版本号、主版本号
        dout.writeShort(CLASSFILE_MINOR_VERSION);
        dout.writeShort(CLASSFILE_MAJOR_VERSION);
        
        // 常量池
        cp.write(dout);
        
        // 访问标志
        dout.writeShort(accessFlags);
        // 类名
        dout.writeShort(cp.getClass(dotToSlash(className)));
        // 父类名(java.lang.reflect.Proxy)
        dout.writeShort(cp.getClass(superclassName));
        // 接口数量
        dout.writeShort(interfaces.length);
        // 接口列表
        for (Class<?> intf : interfaces) {
            dout.writeShort(cp.getClass(
                dotToSlash(intf.getName())));
        }
        // 字段数量 + 字段列表
        dout.writeShort(fields.size());
        for (FieldInfo f : fields) {
            f.write(dout);
        }
        // 方法数量 + 方法列表
        dout.writeShort(methods.size());
        for (MethodInfo m : methods) {
            m.write(dout);
        }
        // 类属性(无)
        dout.writeShort(0);
        
    } catch (IOException e) {
        throw new InternalError("unexpected I/O Exception", e);
    }
    
    return bout.toByteArray();
}

5. 生成的代理类方法示例

java 复制代码
// ProxyMethod.generateMethod() 生成的伪代码

public final void saveUser(String paramString) {
    try {
        // 调用InvocationHandler.invoke()
        // this 是代理对象本身
        // m3 是静态字段中保存的Method对象
        // new Object[]{paramString} 是参数数组
        this.h.invoke(this, m3, new Object[] { paramString });
        return;
    } catch (Error | RuntimeException localError) {
        throw localError;
    } catch (Throwable localThrowable) {
        throw new UndeclaredThrowableException(localThrowable);
    }
}

// 静态初始化代码块生成的伪代码
static {
    try {
        // 获取Method对象并缓存
        m1 = Class.forName("java.lang.Object")
            .getMethod("equals", new Class[] { Class.forName("java.lang.Object") });
        m2 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
        m3 = Class.forName("UserService")
            .getMethod("saveUser", new Class[] { Class.forName("java.lang.String") });
    } catch (NoSuchMethodException localNoSuchMethodException) {
        throw new NoSuchMethodError(localNoSuchMethodException.getMessage());
    } catch (ClassNotFoundException localClassNotFoundException) {
        throw new NoClassDefFoundError(localClassNotFoundException.getMessage());
    }
}

源码深度分析:CGLIB动态代理核心源码逐行解读

1. Enhancer.create() 源码

java 复制代码
// net.sf.cglib.proxy.Enhancer

/**
 * 生成代理类的入口方法
 */
public Object create() {
    // 表示要创建实例(非仅生成类)
    classOnly = false;
    // 使用无参构造器
    argumentTypes = null;
    return createHelper();
}

private Object createHelper() {
    // 【1】预验证:检查final类、java.lang.Class等特殊限制
    preValidate();
    
    // 【2】生成唯一key(基于父类、接口、回调类型组合)
    // KEY_FACTORY是内部接口,用于生成缓存key
    Object key = KEY_FACTORY.newInstance(
        (superclass != null) ? superclass.getName() : null,
        ReflectUtils.getNames(interfaces),
        filter == ALL_ZERO ? null : new WeakCacheKey<CallbackFilter>(filter),
        callbackTypes,
        useFactory,
        interceptDuringConstruction,
        serialVersionUID
    );
    
    // 【3】设置当前key并调用父类的create方法
    this.currentKey = key;
    Object result = super.create(key);
    
    return result;
}

2. AbstractClassGenerator.create() 源码

java 复制代码
// net.sf.cglib.core.AbstractClassGenerator

protected Object create(Object key) {
    try {
        // 获取类加载器数据(包含缓存)
        ClassLoader loader = getClassLoader();
        Map<ClassLoader, ClassLoaderData> cache = CACHE;
        ClassLoaderData data = cache.get(loader);
        if (data == null) {
            synchronized (AbstractClassGenerator.class) {
                cache = CACHE;
                data = cache.get(loader);
                if (data == null) {
                    Map<ClassLoader, ClassLoaderData> newCache 
                        = new WeakHashMap<>(cache);
                    data = new ClassLoaderData(loader);
                    newCache.put(loader, data);
                    CACHE = newCache;
                }
            }
        }
        
        // 设置当前key
        this.key = key;
        
        // 【核心】从缓存获取或生成类
        Object obj = data.get(this, getUseCache());
        
        // 如果是Class对象,创建实例
        if (obj instanceof Class) {
            return firstInstance((Class) obj);
        }
        // 如果是实例,返回下一个实例(用于缓存实例)
        return nextInstance(obj);
        
    } catch (RuntimeException e) {
        throw e;
    } catch (Error e) {
        throw e;
    } catch (Exception e) {
        throw new CodeGenerationException(e);
    }
}

3. ClassLoaderData.get() 源码

java 复制代码
// AbstractClassGenerator.ClassLoaderData

public Object get(AbstractClassGenerator gen, boolean useCache) {
    if (!useCache) {
        // 不使用缓存,直接生成
        return gen.generate(ClassLoaderData.this);
    } else {
        // 使用缓存
        Object cachedValue = generatedClasses.get(gen);
        return gen.unwrapCachedValue(cachedValue);
    }
}

// generatedClasses是LoadingCache,基于FutureTask的并发加载

4. AbstractClassGenerator.generate() 源码

java 复制代码
// 生成代理类的核心方法

protected Class generate(ClassLoaderData data) {
    Class gen;
    
    // 保存当前生成器状态
    Object save = CURRENT.get();
    CURRENT.set(this);
    
    try {
        // 获取类加载器
        ClassLoader classLoader = data.getClassLoader();
        
        if (classLoader == null) {
            throw new IllegalStateException("ClassLoader is null");
        }
        
        synchronized (classLoader) {
            // 生成类名:包名.类名$$EnhancerByCGLIB$$hashCode
            String name = generateClassName(data.getUniqueNamePredicate());
            
            // 设置类名
            data.reserveName(name);
            this.setClassName(name);
        }
        
        // 使用策略生成字节码
        if (attemptLoad) {
            try {
                // 尝试直接加载(如果已存在)
                gen = classLoader.loadClass(getClassName());
            } catch (ClassNotFoundException e) {
                // 不存在,继续生成
            }
        }
        
        // 【核心】调用策略生成字节码
        byte[] b = strategy.generate(this);
        
        // 获取类名
        String className = ClassNameReader.getClassName(new ClassReader(b));
        
        // 转换为ProtectionDomain(如果需要)
        ProtectionDomain protectionDomain = getProtectionDomain();
        
        // 【核心】定义类到JVM
        synchronized (classLoader) {
            if (protectionDomain == null) {
                gen = ReflectUtils.defineClass(
                    className, b, classLoader);
            } else {
                gen = ReflectUtils.defineClass(
                    className, b, classLoader, protectionDomain);
            }
        }
        
        return gen;
        
    } catch (RuntimeException e) {
        throw e;
    } catch (Error e) {
        throw e;
    } catch (Exception e) {
        throw new CodeGenerationException(e);
    } finally {
        CURRENT.set(save);
    }
}

5. DefaultGeneratorStrategy.generate() 源码

java 复制代码
// net.sf.cglib.core.DefaultGeneratorStrategy

public byte[] generate(ClassGenerator cg) throws Exception {
    // 创建ASM ClassWriter
    // COMPUTE_FRAMES:自动计算栈帧(Java 7+需要)
    ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES);
    
    // 创建转换链
    TransformingClassGenerator tfg = new TransformingClassGenerator(
        cg,
        new ClassTransformerChain(new ClassTransformer[]{
            new FieldFilterTransformer(fieldFilter),
            new UndeclaredThrowableTransformer(
                undeclaredThrowable),  // 处理未声明异常
            new MethodInterceptorTransformer(),  // 处理方法拦截
            new NoOpClassTransformer()  // 无操作转换器(占位)
        })
    );
    
    // 生成字节码
    tfg.generateClass(cw);
    
    // 返回字节码数组
    return cw.toByteArray();
}

6. MethodProxy.invokeSuper() 源码(FastClass调用)

java 复制代码
// net.sf.cglib.proxy.MethodProxy

/**
 * 调用父类(目标类)的方法
 * 这是CGLIB性能优化的核心:使用FastClass避免反射
 */
public Object invokeSuper(Object obj, Object[] args) throws Throwable {
    try {
        // 初始化FastClassInfo(懒加载)
        init();
        
        FastClassInfo fci = fastClassInfo;
        
        // 直接通过FastClass索引调用
        // fci.f2: 目标类的FastClass
        // fci.i2: 方法在FastClass中的索引
        return fci.f2.invoke(fci.i2, obj, args);
        
    } catch (InvocationTargetException e) {
        // 包装并抛出目标异常
        throw e.getTargetException();
    }
}

// init() 方法:懒加载FastClass
private void init() {
    if (fastClassInfo == null) {
        // 获取或创建FastClassInfo
        FastClassInfo temp;
        synchronized (initLock) {
            if (fastClassInfo == null) {
                // 创建FastClassInfo
                temp = new FastClassInfo();
                
                // 为目标类创建FastClass
                temp.f1 = helper(ci1, fastClassHooks.getFastClass(ci1));
                // 为代理类创建FastClass
                temp.f2 = helper(ci2, fastClassHooks.getFastClass(ci2));
                
                // 获取方法索引
                temp.i1 = temp.f1.getIndex(sig1);  // 代理类方法索引
                temp.i2 = temp.f2.getIndex(sig2);  // 目标类方法索引
                
                fastClassInfo = temp;
            }
        }
    }
}

// FastClassInfo内部类
private static class FastClassInfo {
    FastClass f1;  // 代理类的FastClass
    FastClass f2;  // 目标类的FastClass
    int i1;        // 代理类方法索引
    int i2;        // 目标类方法索引
}

7. FastClass.invoke() 源码

java 复制代码
// net.sf.cglib.reflect.FastClass

/**
 * FastClass的核心:通过索引直接调用方法
 */
public Object invoke(int index, Object target, Object[] args) 
    throws InvocationTargetException {
    
    // 子类(生成的FastClass)会重写此方法
    // 典型实现如下:
    
    // 伪代码(由ASM生成):
    // switch (index) {
    //     case 12: 
    //         ((OrderService)target).createOrder((Order)args[0]);
    //         return null;
    //     case 13:
    //         return ((OrderService)target).queryOrder((String)args[0]);
    //     // ...
    // }
    
    return invokeMethod(index, target, args);
}

// 生成的FastClass示例方法(伪代码):
public int getIndex(String name, Class[] params) {
    switch(name.hashCode()) {
        case -1182772644:  // "createOrder"
            if (params.length == 1 && params[0] == Order.class) {
                return 12;
            }
            break;
        case -838846263:   // "queryOrder"
            if (params.length == 1 && params[0] == String.class) {
                return 13;
            }
            break;
    }
    return -1;
}

实战案例:完整可运行的JDK动态代理

1. 基础JDK动态代理

java 复制代码
import java.lang.reflect.*;

/**
 * 目标接口
 */
public interface OrderService {
    void createOrder(String orderId);
    String queryOrder(String orderId);
    boolean cancelOrder(String orderId);
}

/**
 * 目标实现
 */
public class OrderServiceImpl implements OrderService {
    @Override
    public void createOrder(String orderId) {
        System.out.println("[业务] 创建订单: " + orderId);
    }
    
    @Override
    public String queryOrder(String orderId) {
        System.out.println("[业务] 查询订单: " + orderId);
        return "Order{id=" + orderId + ", status=PAID}";
    }
    
    @Override
    public boolean cancelOrder(String orderId) {
        System.out.println("[业务] 取消订单: " + orderId);
        return true;
    }
}

/**
 * 日志拦截器(InvocationHandler)
 */
public class LogInvocationHandler implements InvocationHandler {
    private final Object target;
    
    public LogInvocationHandler(Object target) {
        this.target = target;
    }
    
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("[JDK代理] ┌───────────────────────────────");
        System.out.println("[JDK代理] │ 方法: " + method.getDeclaringClass().getName() 
            + "." + method.getName());
        System.out.println("[JDK代理] │ 参数: " + Arrays.toString(args));
        long start = System.currentTimeMillis();
        
        Object result;
        try {
            // 调用目标对象的真实方法
            result = method.invoke(target, args);
            
            long cost = System.currentTimeMillis() - start;
            System.out.println("[JDK代理] │ 结果: " + result);
            System.out.println("[JDK代理] │ 耗时: " + cost + "ms ✓");
            System.out.println("[JDK代理] └───────────────────────────────");
            return result;
            
        } catch (InvocationTargetException e) {
            long cost = System.currentTimeMillis() - start;
            System.out.println("[JDK代理] │ 异常: " + e.getTargetException().getMessage());
            System.out.println("[JDK代理] │ 耗时: " + cost + "ms ✗");
            System.out.println("[JDK代理] └───────────────────────────────");
            throw e.getTargetException();
        }
    }
    
    /**
     * 创建代理对象的工厂方法
     */
    @SuppressWarnings("unchecked")
    public static <T> T createProxy(Object target, Class<T> iface) {
        return (T) Proxy.newProxyInstance(
            target.getClass().getClassLoader(),
            new Class<?>[]{iface},
            new LogInvocationHandler(target)
        );
    }
}

/**
 * 测试类
 */
public class JdkProxyTest {
    public static void main(String[] args) {
        // 创建目标对象
        OrderService target = new OrderServiceImpl();
        
        // 创建代理对象
        OrderService proxy = LogInvocationHandler.createProxy(
            target, OrderService.class);
        
        System.out.println("=== JDK动态代理测试 ===\n");
        
        // 调用代理方法
        proxy.createOrder("ORD-2024-001");
        System.out.println();
        
        String result = proxy.queryOrder("ORD-2024-001");
        System.out.println("返回值: " + result);
        System.out.println();
        
        boolean cancelled = proxy.cancelOrder("ORD-2024-001");
        System.out.println("取消结果: " + cancelled);
        
        // 验证代理类信息
        System.out.println("\n=== 代理类信息 ===");
        System.out.println("类名: " + proxy.getClass().getName());
        System.out.println("父类: " + proxy.getClass().getSuperclass().getName());
        System.out.println("实现接口: ");
        for (Class<?> intf : proxy.getClass().getInterfaces()) {
            System.out.println("  - " + intf.getName());
        }
    }
}

运行结果

复制代码
=== JDK动态代理测试 ===

[JDK代理] ┌───────────────────────────────
[JDK代理] │ 方法: OrderService.createOrder
[JDK代理] │ 参数: [ORD-2024-001]
[业务] 创建订单: ORD-2024-001
[JDK代理] │ 结果: null
[JDK代理] │ 耗时: 1ms ✓
[JDK代理] └───────────────────────────────

[JDK代理] ┌───────────────────────────────
[JDK代理] │ 方法: OrderService.queryOrder
[JDK代理] │ 参数: [ORD-2024-001]
[业务] 查询订单: ORD-2024-001
[JDK代理] │ 结果: Order{id=ORD-2024-001, status=PAID}
[JDK代理] │ 耗时: 0ms ✓
[JDK代理] └───────────────────────────────
返回值: Order{id=ORD-2024-001, status=PAID}

=== 代理类信息 ===
类名: com.sun.proxy.$Proxy0
父类: java.lang.reflect.Proxy
实现接口: 
  - OrderService

2. 查看JDK动态代理生成的类文件

java 复制代码
public class ProxyClassDumper {
    public static void main(String[] args) {
        // 设置系统属性:保存生成的代理类文件
        System.setProperty("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
        
        OrderService target = new OrderServiceImpl();
        OrderService proxy = LogInvocationHandler.createProxy(
            target, OrderService.class);
        
        proxy.createOrder("TEST-001");
        
        // 生成的.class文件将保存在当前目录的 com/sun/proxy/ 下
        // 使用 javap -c com.sun.proxy.$Proxy0 可以查看反汇编代码
    }
}

实战案例:完整可运行的CGLIB动态代理

1. 基础CGLIB动态代理

java 复制代码
import net.sf.cglib.proxy.*;

/**
 * 没有接口的目标类
 */
public class UserService {
    
    public void saveUser(String name) {
        System.out.println("[业务] 保存用户: " + name);
    }
    
    public String getUser(Long id) {
        System.out.println("[业务] 查询用户: " + id);
        return "User{id=" + id + ", name=张三}";
    }
    
    public boolean deleteUser(Long id) {
        System.out.println("[业务] 删除用户: " + id);
        return true;
    }
    
    // final方法不会被代理
    public final void finalMethod() {
        System.out.println("[业务] final方法");
    }
}

/**
 * CGLIB拦截器(MethodInterceptor)
 */
public class LogMethodInterceptor implements MethodInterceptor {
    
    @Override
    public Object intercept(Object obj, Method method, Object[] args, 
                           MethodProxy proxy) throws Throwable {
        System.out.println("[CGLIB代理] ┌───────────────────────────────");
        System.out.println("[CGLIB代理] │ 方法: " + method.getDeclaringClass().getName() 
            + "." + method.getName());
        System.out.println("[CGLIB代理] │ 参数: " + Arrays.toString(args));
        long start = System.currentTimeMillis();
        
        Object result;
        try {
            // 使用invokeSuper调用父类方法,比反射快
            // 注意:这里必须使用invokeSuper,而不是invoke
            result = proxy.invokeSuper(obj, args);
            
            long cost = System.currentTimeMillis() - start;
            System.out.println("[CGLIB代理] │ 结果: " + result);
            System.out.println("[CGLIB代理] │ 耗时: " + cost + "ms ✓");
            System.out.println("[CGLIB代理] └───────────────────────────────");
            return result;
            
        } catch (Throwable t) {
            long cost = System.currentTimeMillis() - start;
            System.out.println("[CGLIB代理] │ 异常: " + t.getMessage());
            System.out.println("[CGLIB代理] │ 耗时: " + cost + "ms ✗");
            System.out.println("[CGLIB代理] └───────────────────────────────");
            throw t;
        }
    }
    
    /**
     * 创建代理对象的工厂方法
     */
    @SuppressWarnings("unchecked")
    public static <T> T createProxy(Class<T> clazz) {
        Enhancer enhancer = new Enhancer();
        // 设置父类(目标类)
        enhancer.setSuperclass(clazz);
        // 设置回调
        enhancer.setCallback(new LogMethodInterceptor());
        return (T) enhancer.create();
    }
}

/**
 * 测试类
 */
public class CglibProxyTest {
    public static void main(String[] args) {
        // 创建代理对象
        UserService proxy = LogMethodInterceptor.createProxy(UserService.class);
        
        System.out.println("=== CGLIB动态代理测试 ===\n");
        
        proxy.saveUser("李四");
        System.out.println();
        
        String result = proxy.getUser(1001L);
        System.out.println("返回值: " + result);
        System.out.println();
        
        boolean deleted = proxy.deleteUser(1001L);
        System.out.println("删除结果: " + deleted);
        System.out.println();
        
        // final方法不会被拦截
        System.out.println("=== final方法测试 ===");
        proxy.finalMethod();
        
        // 验证代理类信息
        System.out.println("\n=== 代理类信息 ===");
        System.out.println("类名: " + proxy.getClass().getName());
        System.out.println("父类: " + proxy.getClass().getSuperclass().getName());
    }
}

运行结果

复制代码
=== CGLIB动态代理测试 ===

[CGLIB代理] ┌───────────────────────────────
[CGLIB代理] │ 方法: UserService.saveUser
[CGLIB代理] │ 参数: [李四]
[业务] 保存用户: 李四
[CGLIB代理] │ 结果: null
[CGLIB代理] │ 耗时: 1ms ✓
[CGLIB代理] └───────────────────────────────

=== final方法测试 ===
[业务] final方法

=== 代理类信息 ===
类名: UserService$$EnhancerByCGLIB$$12345678
父类: UserService

2. CGLIB多种Callback组合

java 复制代码
import net.sf.cglib.proxy.*;

/**
 * 固定值返回拦截器
 */
public class FixedValueInterceptor implements FixedValue {
    @Override
    public Object loadObject() throws Exception {
        return "固定返回值";
    }
}

/**
 * 懒加载拦截器
 */
public class LazyLoaderInterceptor implements LazyLoader {
    @Override
    public Object loadObject() throws Exception {
        System.out.println("[懒加载] 初始化重对象...");
        return new HeavyObject();
    }
}

/**
 * 多Callback配置示例
 */
public class MultiCallbackTest {
    public static void main(String[] args) {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(UserService.class);
        
        // 设置多个回调
        Callback[] callbacks = new Callback[]{
            new LogMethodInterceptor(),    // 索引0:日志拦截
            new FixedValueInterceptor(),    // 索引1:固定值返回
            NoOp.INSTANCE                   // 索引2:无操作
        };
        
        enhancer.setCallbacks(callbacks);
        
        // 设置回调过滤器:根据方法选择使用哪个回调
        enhancer.setCallbackFilter(new CallbackFilter() {
            @Override
            public int accept(Method method) {
                if (method.getName().equals("getUser")) {
                    return 1; // 使用FixedValueInterceptor
                } else if (method.getName().equals("finalMethod")) {
                    return 2; // 使用NoOp(不拦截)
                }
                return 0; // 默认使用LogMethodInterceptor
            }
        });
        
        UserService proxy = (UserService) enhancer.create();
        
        System.out.println("=== 多Callback测试 ===");
        proxy.saveUser("王五");  // 使用日志拦截
        System.out.println();
        
        String result = proxy.getUser(1L);  // 使用固定值返回
        System.out.println("返回值: " + result);
    }
}

实战案例:基于动态代理的迷你AOP框架

1. 核心注解与接口

java 复制代码
import java.lang.annotation.*;

/**
 * 环绕通知注解
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Around {
    Class<? extends Interceptor>[] value();
}

/**
 * 拦截器接口
 */
public interface Interceptor {
    Object intercept(Invocation invocation) throws Throwable;
}

/**
 * 调用链上下文
 */
public class Invocation {
    private final Object target;
    private final Method method;
    private final Object[] args;
    private final Interceptor[] interceptors;
    private int index;
    
    public Invocation(Object target, Method method, Object[] args, 
                     Interceptor[] interceptors) {
        this.target = target;
        this.method = method;
        this.args = args;
        this.interceptors = interceptors;
        this.index = 0;
    }
    
    /**
     * 推进调用链
     */
    public Object proceed() throws Throwable {
        if (index < interceptors.length) {
            return interceptors[index++].intercept(this);
        }
        return method.invoke(target, args);
    }
    
    public Method getMethod() { return method; }
    public Object[] getArgs() { return args; }
    public Object getTarget() { return target; }
}

2. 拦截器实现

java 复制代码
/**
 * 日志拦截器
 */
public class LogInterceptor implements Interceptor {
    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        String name = invocation.getMethod().getName();
        System.out.println("[AOP-Log] → 进入方法: " + name);
        long start = System.currentTimeMillis();
        
        Object result = invocation.proceed();
        
        long cost = System.currentTimeMillis() - start;
        System.out.println("[AOP-Log] ← 退出方法: " + name + ", 耗时: " + cost + "ms");
        return result;
    }
}

/**
 * 事务拦截器
 */
public class TransactionInterceptor implements Interceptor {
    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        String name = invocation.getMethod().getName();
        System.out.println("[AOP-TX] 开启事务: " + name);
        
        try {
            Object result = invocation.proceed();
            System.out.println("[AOP-TX] 提交事务: " + name);
            return result;
            
        } catch (Exception e) {
            System.out.println("[AOP-TX] 回滚事务: " + name + ", 原因: " + e.getMessage());
            throw e;
        }
    }
}

/**
 * 权限拦截器
 */
public class AuthInterceptor implements Interceptor {
    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        System.out.println("[AOP-Auth] 校验权限: " + invocation.getMethod().getName());
        // 模拟权限校验
        System.out.println("[AOP-Auth] 权限校验通过 ✓");
        return invocation.proceed();
    }
}

3. 代理工厂

java 复制代码
/**
 * AOP代理工厂
 */
public class AopProxyFactory {
    
    /**
     * 为目标对象创建AOP代理
     */
    @SuppressWarnings("unchecked")
    public static <T> T createProxy(T target) {
        Class<?> clazz = target.getClass();
        Class<?>[] interfaces = clazz.getInterfaces();
        
        if (interfaces.length == 0) {
            // 无接口,使用CGLIB
            return createCglibProxy(target);
        }
        
        // 有接口,使用JDK动态代理
        return (T) Proxy.newProxyInstance(
            clazz.getClassLoader(),
            interfaces,
            (proxy, method, args) -> {
                Around around = method.getAnnotation(Around.class);
                if (around == null) {
                    // 无注解,直接调用
                    return method.invoke(target, args);
                }
                
                // 创建拦截器链
                Interceptor[] interceptors = new Interceptor[around.value().length];
                for (int i = 0; i < around.value().length; i++) {
                    interceptors[i] = around.value()[i]
                        .getDeclaredConstructor().newInstance();
                }
                
                // 执行拦截器链
                Invocation invocation = new Invocation(
                    target, method, args, interceptors);
                return invocation.proceed();
            }
        );
    }
    
    /**
     * CGLIB代理创建
     */
    @SuppressWarnings("unchecked")
    private static <T> T createCglibProxy(T target) {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(target.getClass());
        enhancer.setCallback((MethodInterceptor) (obj, method, args, proxy) -> {
            Around around = method.getAnnotation(Around.class);
            if (around == null) {
                return proxy.invokeSuper(obj, args);
            }
            
            Interceptor[] interceptors = new Interceptor[around.value().length];
            for (int i = 0; i < around.value().length; i++) {
                interceptors[i] = around.value()[i]
                    .getDeclaredConstructor().newInstance();
            }
            
            Invocation invocation = new Invocation(
                target, method, args, interceptors);
            return invocation.proceed();
        });
        return (T) enhancer.create();
    }
}

4. 业务接口与实现

java 复制代码
/**
 * 支付服务接口
 */
public interface PayService {
    
    @Around({LogInterceptor.class, AuthInterceptor.class, TransactionInterceptor.class})
    void pay(String orderId, double amount);
    
    @Around({LogInterceptor.class})
    String queryPayStatus(String orderId);
    
    // 无注解,不拦截
    String getServiceName();
}

/**
 * 支付服务实现
 */
public class PayServiceImpl implements PayService {
    
    @Override
    public void pay(String orderId, double amount) {
        System.out.println("[业务] 支付订单: " + orderId + ", 金额: ¥" + amount);
    }
    
    @Override
    public String queryPayStatus(String orderId) {
        System.out.println("[业务] 查询支付状态: " + orderId);
        return "PAID";
    }
    
    @Override
    public String getServiceName() {
        return "PayService_v1.0";
    }
}

5. 测试类

java 复制代码
/**
 * 迷你AOP框架测试
 */
public class MiniAopTest {
    public static void main(String[] args) {
        System.out.println("=== 迷你AOP框架测试 ===\n");
        
        // 创建目标对象和代理对象
        PayService target = new PayServiceImpl();
        PayService proxy = AopProxyFactory.createProxy(target);
        
        // 测试1:多拦截器链
        System.out.println("--- 测试1:支付(日志+权限+事务) ---");
        proxy.pay("2024001", 199.99);
        System.out.println();
        
        // 测试2:单拦截器
        System.out.println("--- 测试2:查询状态(仅日志) ---");
        String status = proxy.queryPayStatus("2024001");
        System.out.println("查询结果: " + status);
        System.out.println();
        
        // 测试3:无拦截器
        System.out.println("--- 测试3:获取服务名(无拦截) ---");
        String name = proxy.getServiceName();
        System.out.println("服务名: " + name);
    }
}

运行结果

复制代码
=== 迷你AOP框架测试 ===

--- 测试1:支付(日志+权限+事务) ---
[AOP-Log] → 进入方法: pay
[AOP-Auth] 校验权限: pay
[AOP-Auth] 权限校验通过 ✓
[AOP-TX] 开启事务: pay
[业务] 支付订单: 2024001, 金额: ¥199.99
[AOP-TX] 提交事务: pay
[AOP-Log] ← 退出方法: pay, 耗时: 2ms

--- 测试2:查询状态(仅日志) ---
[AOP-Log] → 进入方法: queryPayStatus
[业务] 查询支付状态: 2024001
[AOP-Log] ← 退出方法: queryPayStatus, 耗时: 1ms
查询结果: PAID

--- 测试3:获取服务名(无拦截) ---
服务名: PayService_v1.0

对比分析:JDK动态代理 vs CGLIB vs AspectJ vs Javassist

1. 四种代理技术全方位对比

复制代码
代理技术对比矩阵:

┌────────────────┬─────────────┬─────────────┬─────────────┬─────────────┐
│    特性        │ JDK动态代理  │   CGLIB     │   AspectJ   │  Javassist  │
├────────────────┼─────────────┼─────────────┼─────────────┼─────────────┤
│ 代理方式       │ 实现接口     │ 继承类       │ 字节码织入   │ 字节码生成   │
├────────────────┼─────────────┼─────────────┼─────────────┼─────────────┤
│ 依赖           │ JDK内置      │ 第三方库      │ 编译器插件   │ 第三方库     │
├────────────────┼─────────────┼─────────────┼─────────────┼─────────────┤
│ 目标要求       │ 必须实现接口  │ 非final类    │ 任何类/方法  │ 任何类       │
├────────────────┼─────────────┼─────────────┼─────────────┼─────────────┤
│ 方法限制       │ 无           │ 不能代理final │ 无限制       │ 无           │
│                │              │ 和static方法  │             │              │
├────────────────┼─────────────┼─────────────┼─────────────┼─────────────┤
│ 调用机制       │ 反射调用     │ FastClass    │ 直接调用     │ 直接调用     │
│                │ Method.invoke│ 索引调用      │(字节码替换)│(生成类)    │
├────────────────┼─────────────┼─────────────┼─────────────┼─────────────┤
│ 性能           │ 较慢(反射)  │ 较快         │ 最快(原生)  │ 较快         │
│ 相对直接调用   │ ~15-20x     │ ~1.2-2x     │ ~1x(无损耗)│ ~2-3x       │
├────────────────┼─────────────┼─────────────┼─────────────┼─────────────┤
│ 生成速度       │ 快           │ 较慢         │ 编译时完成   │ 中等         │
├────────────────┼─────────────┼─────────────┼─────────────┼─────────────┤
│ 内存占用       │ 小           │ 较大         │ 无额外内存   │ 中等         │
├────────────────┼─────────────┼─────────────┼─────────────┼─────────────┤
│ 侵入性         │ 低           │ 低           │ 高(需工具)  │ 低           │
├────────────────┼─────────────┼─────────────┼─────────────┼─────────────┤
│ 调试难度       │ 低           │ 中等         │ 高           │ 中等         │
├────────────────┼─────────────┼─────────────┼─────────────┼─────────────┤
│ 适用场景       │ 有接口的类   │ 无接口的类   │ 极致性能AOP  │ 运行时字节码 │
│               │ Spring默认   │ SpringBoot默认│ 金融交易系统  │ 操作        │
└────────────────┴─────────────┴─────────────┴─────────────┴─────────────┘

2. 详细特性对比

特性 JDK动态代理 CGLIB AspectJ Javassist
代理方式 实现接口 继承类 字节码织入 字节码生成
依赖 JDK内置 cglib:cglib:3.x AspectJ编译器/加载器 org.javassist:javassist
目标要求 必须实现接口 非final类,非static方法 任何类/方法 任何类
方法限制 仅代理接口方法 不能代理final/static方法 无限制 无限制
调用机制 反射调用 FastClass索引调用 直接字节码调用 直接调用
性能 较慢(15-20x) 较快(1.2-2x) 最快(1x) 较快(2-3x)
生成速度 较慢 编译时 中等
内存占用 小(单类) 较大(代理+FastClass) 无额外内存 中等
侵入性
调试难度 低(可dump类文件) 中等 中等
学习曲线 中等 中等
典型应用 Spring AOP(默认) Spring Boot AOP(默认) 金融交易系统 Hibernate

3. 静态代理 vs 动态代理

复制代码
静态代理 vs 动态代理:

┌─────────────────┬──────────────────┬──────────────────┐
│     特性        │     静态代理      │     动态代理      │
├─────────────────┼──────────────────┼──────────────────┤
│ 代码生成时机     │ 编译前手写        │ 运行时自动生成     │
├─────────────────┼──────────────────┼──────────────────┤
│ 代码冗余        │ 高(每个目标类    │ 低(通用工厂适配   │
│               │  都需代理类)     │  所有接口/类)     │
├─────────────────┼──────────────────┼──────────────────┤
│ 维护成本        │ 高(接口变更需    │ 低(自动生成,    │
│               │  同步修改代理类)  │  无需手动维护)    │
├─────────────────┼──────────────────┼──────────────────┤
│ 灵活性          │ 低(代理逻辑固定)│ 高(运行时决定    │
│               │                  │  代理行为)        │
├─────────────────┼──────────────────┼──────────────────┤
│ 性能            │ 直接调用(无损耗)│ 有代理开销        │
├─────────────────┼──────────────────┼──────────────────┤
│ 适用场景        │ 代理逻辑固定、    │ 通用横切逻辑      │
│               │ 目标类数量少      │(日志、事务、权限)│
└─────────────────┴──────────────────┴──────────────────┘

4. 性能差异分析

复制代码
方法调用性能对比(相对倍数,直接调用=1x):

直接调用:        ████ 1x(基准)
                  
AspectJ织入:     ████ 1x(无额外开销)
                  
CGLIB invokeSuper: ████ 1.2x(FastClass switch跳转)
                  
Javassist代理:    ████████ 2.5x(直接调用,少量开销)
                  
CGLIB intercept:  ████████████████████ 20x(反射+额外逻辑)
                  
JDK代理:         ████████████████████████████████ 15-20x(反射调用)
                  
反射直接调用:     ████████████████████████████████ 15-20x

说明:
- CGLIB使用invokeSuper时性能接近原生
- CGLIB使用intercept+反射时性能与JDK代理相当
- JDK代理的性能损耗主要在Method.invoke()的反射开销

性能分析:Benchmark数据与复杂度分析

1. JMH基准测试代码

java 复制代码
import org.openjdk.jmh.annotations.*;
import org.openjdk.jmh.runner.Runner;
import org.openjdk.jmh.runner.options.Options;
import org.openjdk.jmh.runner.options.OptionsBuilder;

import java.lang.reflect.*;
import java.util.concurrent.TimeUnit;

/**
 * JMH性能基准测试
 * 
 * 运行方式:
 * mvn dependency:copy -Dartifact=org.openjdk.jmh:jmh-core:1.37
 * javac -cp jmh-core-1.37.jar:jmh-generator-annprocess-1.37.jar *.java
 * java -cp .:jmh-core-1.37.jar:jmh-generator-annprocess-1.37.jar ProxyBenchmark
 */
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
@State(Scope.Thread)
@Warmup(iterations = 3, time = 1)
@Measurement(iterations = 5, time = 1)
@Fork(1)
public class ProxyBenchmark {
    
    private OrderService target;
    private OrderService jdkProxy;
    private OrderService cglibProxy;
    private Method targetMethod;
    private Method proxyMethod;
    
    @Setup
    public void setup() throws Exception {
        // 目标对象
        target = new OrderServiceImpl();
        
        // JDK动态代理
        jdkProxy = (OrderService) Proxy.newProxyInstance(
            target.getClass().getClassLoader(),
            new Class<?>[]{OrderService.class},
            new InvocationHandler() {
                @Override
                public Object invoke(Object proxy, Method method, Object[] args) 
                    throws Throwable {
                    return method.invoke(target, args);
                }
            }
        );
        
        // CGLIB代理(使用NoOp避免额外逻辑)
        net.sf.cglib.proxy.Enhancer enhancer = new net.sf.cglib.proxy.Enhancer();
        enhancer.setSuperclass(OrderServiceImpl.class);
        enhancer.setCallback(new net.sf.cglib.proxy.MethodInterceptor() {
            @Override
            public Object intercept(Object obj, Method method, Object[] args,
                                   net.sf.cglib.proxy.MethodProxy proxy) 
                throws Throwable {
                return proxy.invokeSuper(obj, args);
            }
        });
        cglibProxy = (OrderService) enhancer.create();
        
        // 预取Method对象
        targetMethod = OrderServiceImpl.class.getMethod("createOrder", String.class);
        proxyMethod = OrderService.class.getMethod("createOrder", String.class);
    }
    
    @Benchmark
    public void directCall() {
        target.createOrder("TEST-001");
    }
    
    @Benchmark
    public void jdkProxyCall() {
        jdkProxy.createOrder("TEST-001");
    }
    
    @Benchmark
    public void cglibProxyCall() {
        cglibProxy.createOrder("TEST-001");
    }
    
    @Benchmark
    public void reflectionCall() throws Exception {
        targetMethod.invoke(target, "TEST-001");
    }
    
    public static void main(String[] args) throws Exception {
        Options opt = new OptionsBuilder()
            .include(ProxyBenchmark.class.getSimpleName())
            .build();
        new Runner(opt).run();
    }
}

2. 基准测试结果分析

复制代码
JMH基准测试结果(典型值,单位:纳秒/调用):

Benchmark                         Mode  Cnt   Score   Error  Units
------------------------------------------------------------------
ProxyBenchmark.directCall         avgt    5    5.2 ± 0.3   ns/op
ProxyBenchmark.cglibProxyCall     avgt    5    7.1 ± 0.5   ns/op
ProxyBenchmark.reflectionCall     avgt    5   85.3 ± 4.2   ns/op
ProxyBenchmark.jdkProxyCall       avgt    5   92.6 ± 5.1   ns/op

性能分析:
┌─────────────────┬──────────┬────────────────────────────────────┐
│     调用方式     │ 相对性能  │              原因分析               │
├─────────────────┼──────────┼────────────────────────────────────┤
│ 直接调用         │ 1x       │ 直接字节码调用,可被JIT内联优化      │
├─────────────────┼──────────┼────────────────────────────────────┤
│ CGLIB invokeSuper│ 1.4x     │ FastClass switch跳转,几乎无额外开销 │
├─────────────────┼──────────┼────────────────────────────────────┤
│ 反射调用         │ 16.4x    │ Method.invoke()需检查可见性、       │
│                 │          │ 参数转换、JNI调用,无法内联          │
├─────────────────┼──────────┼────────────────────────────────────┤
│ JDK代理          │ 17.8x    │ 反射调用 + 代理层转发开销            │
└─────────────────┴──────────┴────────────────────────────────────┘

3. 复杂度分析

复制代码
代理类生成的复杂度:

时间复杂度:
- JDK代理:O(n),n为接口方法数
  ├── 生成类头:O(1)
  ├── 遍历接口方法:O(n)
  ├── 生成每个方法的字节码:O(1)
  └── 写入类文件:O(n)
  
- CGLIB:O(n),n为目标类方法数
  ├── ASM遍历目标类:O(n)
  ├── 为每个方法生成代理:O(1)
  ├── 生成FastClass:O(n)
  └── 常量和方法数常数更大

空间复杂度:
- JDK代理:O(n)
  ├── 类结构:O(1)
  ├── 静态Method字段:O(n)
  └── 方法字节码:O(n)
  
- CGLIB:O(n)
  ├── 代理类:O(n)
  ├── FastClass类:O(n)
  └── 总体内存占用是JDK的2-3倍

调用时间复杂度:
- 直接调用:O(1)
- JDK代理:O(1),但常数大(反射+JNI)
- CGLIB FastClass:O(1),常数小(switch跳转)

4. 性能优化建议

复制代码
动态代理性能优化策略:

1. 代理类缓存
   ┌─────────────────────────────────────────┐
   │  JDK Proxy:内置WeakCache,无需额外处理  │
   │  CGLIB:内置缓存,但注意key的生成策略     │
   └─────────────────────────────────────────┘

2. 减少反射调用
   ┌─────────────────────────────────────────┐
   │  JDK代理:Method对象已在静态块缓存        │
   │  CGLIB:优先使用invokeSuper而非invoke     │
   │  通用:缓存Method对象,避免重复getMethod() │
   └─────────────────────────────────────────┘

3. 避免代理嵌套
   ┌─────────────────────────────────────────┐
   │  代理A包装代理B,会导致双重转发开销        │
   │  如需多层代理,考虑责任链模式替代          │
   └─────────────────────────────────────────┘

4. 选择合适代理技术
   ┌─────────────────────────────────────────┐
   │  高频调用(>10000次/秒):考虑AspectJ    │
   │  中频调用(1000-10000次/秒):CGLIB      │
   │  低频调用(<1000次/秒):JDK代理         │
   └─────────────────────────────────────────┘

常见陷阱与最佳实践

陷阱1:InvocationHandler中递归调用proxy导致栈溢出

java 复制代码
// ❌ 错误示例:StackOverflowError
public class WrongInvocationHandler implements InvocationHandler {
    private final Object target;
    
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("开始调用...");
        // 致命错误:调用proxy会再次触发invoke(),导致无限递归
        return method.invoke(proxy, args); // StackOverflowError!
    }
}

// ✅ 正确示例:调用target真实对象
public class CorrectInvocationHandler implements InvocationHandler {
    private final Object target;
    
    public CorrectInvocationHandler(Object target) {
        this.target = target;
    }
    
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("开始调用...");
        // 正确:调用目标对象,而非代理对象
        return method.invoke(target, args);
    }
}

陷阱2:同类方法调用导致代理失效(Spring AOP经典问题)

java 复制代码
@Service
public class OrderService {
    
    @Transactional
    public void createOrder(Order order) {
        // 事务逻辑...
        saveOrderItem(order); // ❌ 直接调用,代理不生效
    }
    
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void saveOrderItem(Order order) {
        // 需要独立事务,但此处不会生效!
    }
}

/*
原因分析:

调用方 ──► OrderService代理对象
              │
              ▼
         createOrder()
              │
              ├── 事务拦截器生效(开启事务)
              ├── this.saveOrderItem()  ◄── 注意:这里是this!
              │       │
              │       └── 直接调用目标方法,不走代理
              │           事务拦截器不生效
              └── 事务提交

解决方案:
*/

// 方案1:注入自身代理(不推荐,循环依赖风险)
@Service
public class OrderService {
    @Autowired
    private OrderService self; // 注入代理对象
    
    public void createOrder(Order order) {
        self.saveOrderItem(order); // ✅ 通过代理调用
    }
}

// 方案2:使用AopContext获取当前代理(推荐)
@Service
public class OrderService {
    
    public void createOrder(Order order) {
        // 获取当前代理对象
        ((OrderService) AopContext.currentProxy())
            .saveOrderItem(order); // ✅ 通过代理调用
    }
}
// 注意:需配置@EnableAspectJAutoProxy(exposeProxy = true)

// 方案3:拆分到不同类(最佳实践)
@Service
public class OrderService {
    @Autowired
    private OrderItemService itemService;
    
    public void createOrder(Order order) {
        itemService.saveOrderItem(order); // ✅ 不同类,代理生效
    }
}

陷阱3:忽略CGLIB对final的限制

java 复制代码
// ❌ 错误:final类无法被CGLIB代理
public final class UserService { 
    public void save() { }
}

// ❌ 错误:final方法不会被拦截
public class UserService {
    public final void save() { } // CGLIB无法重写此方法
}

// ✅ 正确:需要代理的方法不要声明为final
public class UserService {
    public void save() { } // CGLIB可以重写并拦截
}

陷阱4:忽略类加载器隔离问题

java 复制代码
// ❌ 错误:接口和目标类由不同类加载器加载
ClassLoader interfaceLoader = Interface.class.getClassLoader();
ClassLoader targetLoader = target.getClass().getClassLoader();

// 如果两者不一致,可能导致 ClassCastException
// 或 ClassNotFoundException

// ✅ 正确:使用统一的类加载器
ClassLoader loader = target.getClass().getClassLoader();
// 确保接口也能被该加载器加载

// 在OSGi、Tomcat等多层类加载器环境中尤其要注意

陷阱5:JDK代理的equals/hashCode陷阱

java 复制代码
// JDK代理继承java.lang.Proxy,equals/hashCode行为特殊
// 如果InvocationHandler实现不当,可能导致问题

// ❌ 错误示例:代理对象无法正确放入HashMap
Map<Proxy, String> map = new HashMap<>();
map.put(proxy1, "value1");
// proxy1.equals(proxy2) 会调用InvocationHandler.invoke()
// 如果handler逻辑不当,可能导致不一致

// ✅ 正确做法
public class SafeInvocationHandler implements InvocationHandler {
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // 对Object的方法(equals/hashCode/toString)特殊处理
        if (method.getDeclaringClass() == Object.class) {
            return method.invoke(target, args);
        }
        // 其他方法走代理逻辑
        return method.invoke(target, args);
    }
}

陷阱6:CGLIB代理对象的类型判断

java 复制代码
// ❌ 错误:使用getClass() == UserService.class判断
UserService proxy = CglibProxy.createProxy(UserService.class);
if (proxy.getClass() == UserService.class) { // false!
    // 永远不会执行
}

// ✅ 正确:使用instanceof判断
if (proxy instanceof UserService) { // true
    // 正确
}

// ✅ 正确:Spring中判断是否是代理对象
if (AopUtils.isAopProxy(proxy)) {
    // 是代理对象
}

if (AopUtils.isJdkDynamicProxy(proxy)) {
    // JDK动态代理
}

if (AopUtils.isCglibProxy(proxy)) {
    // CGLIB代理
}

陷阱7:代理对象的序列化问题

java 复制代码
// JDK代理:实现Serializable接口时需注意
// 代理类默认不实现Serializable,即使目标接口实现了

// ✅ 正确:确保InvocationHandler实现Serializable
public class SerializableHandler implements InvocationHandler, Serializable {
    private final Object target;
    
    public SerializableHandler(Object target) {
        this.target = target;
    }
    // ...
}

// CGLIB代理:需要实现Factory接口才能正确序列化
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(Target.class);
enhancer.setCallback(callback);
enhancer.setUseFactory(true); // 启用Factory接口

最佳实践总结

复制代码
动态代理最佳实践清单:

┌─────────────────────────────────────────────────────────────┐
│ 1. 设计层面                                                  │
│    ├── 优先基于接口设计(便于JDK代理,减少依赖)              │
│    ├── 避免final类/方法(兼容CGLIB代理)                    │
│    └── 同类内部调用需考虑代理失效问题                        │
├─────────────────────────────────────────────────────────────┤
│ 2. 性能层面                                                  │
│    ├── 高频场景考虑AspectJ编译时织入                         │
│    ├── CGLIB优先使用invokeSuper                              │
│    └── 避免多层代理嵌套                                      │
├─────────────────────────────────────────────────────────────┤
│ 3. 调试层面                                                  │
│    ├── 设置-Dsun.misc.ProxyGenerator.saveGeneratedFiles=true │
│    ├── 使用javap -c反汇编查看生成的类                        │
│    └── Spring中设置@EnableAspectJAutoProxy(exposeProxy=true) │
├─────────────────────────────────────────────────────────────┤
│ 4. 类加载器层面                                              │
│    ├── 确保代理类加载器能加载目标接口                        │
│    ├── OSGi/Tomcat环境注意类加载器隔离                       │
│    └── 避免接口和目标类由不同加载器加载                      │
├─────────────────────────────────────────────────────────────┤
│ 5. Spring集成层面                                            │
│    ├── 优先使用接口:自动使用JDK代理                         │
│    ├── 无接口时开启proxyTargetClass=true使用CGLIB            │
│    ├── 注意@Async、@Transactional的代理顺序                  │
│    └── 同类调用使用AopContext.currentProxy()                 │
└─────────────────────────────────────────────────────────────┘

面试题与参考答案

面试题1:为什么JDK动态代理调用方法比直接调用慢?

参考答案

JDK动态代理慢主要有三个原因:

  1. 反射调用开销Method.invoke() 需要进行运行时检查(方法可见性、参数类型匹配),并通过JNI调用Native方法
  2. 代理层转发 :调用经过 $Proxy0InvocationHandler.invoke() → 反射调用目标方法,多了两层转发
  3. 无法内联优化:JVM JIT编译器难以对反射调用进行方法内联优化

JDK 8后对反射做了优化(使用 MethodAccessor 生成字节码),但仍有性能差距。对性能极端敏感的场景,可用 MethodHandleLambdaMetafactory 替代。

复制代码
调用链路对比:

直接调用:
调用方 ──► 目标方法(直接跳转,可内联)

JDK代理:
调用方 ──► $Proxy0.saveUser()
              └── super.h.invoke(this, m3, args)
                      └── InvocationHandler.invoke()
                              └── Method.invoke(target, args)
                                      └── JNI Native调用
                                              └── 目标方法

面试题2:CGLIB的FastClass机制是什么?为什么它比反射快?

参考答案

FastClass是CGLIB生成的辅助类,核心思想是用整数索引替代方法名+参数类型的字符串匹配

java 复制代码
// FastClass的典型实现(由ASM生成)
public int getIndex(String name, Class[] params) {
    // 通过hashCode快速定位
    switch(name.hashCode()) {
        case -1182772644:
            if (params.length == 1 && params[0] == Order.class) {
                return 12; // 直接返回索引
            }
    }
    return -1;
}

public Object invoke(int index, Object target, Object[] args) {
    switch (index) {
        case 12: 
            ((OrderService)target).createOrder((Order)args[0]);
            return null;
        // ...
    }
}

为什么比反射快

  • 反射调用Method.invoke() 需要解析方法签名、检查访问权限、JNI调用
  • FastClassswitch(index) 直接跳转到方法调用,是本地Java调用
  • 性能对比:FastClass接近直接调用(~1.2x),反射调用慢15-20倍

面试题3:Spring中@Transactional失效的几种场景?

参考答案

Spring AOP基于动态代理实现,@Transactional失效的常见场景:

  1. 同类内部方法调用(this调用不走代理)

    java 复制代码
    public void methodA() {
        this.methodB(); // @Transactional失效
    }
  2. 方法不是public@Transactional默认只能应用于public方法

  3. 异常被吞掉或未抛给代理层

    java 复制代码
    @Transactional
    public void method() {
        try {
            // 业务逻辑
        } catch (Exception e) {
            // 吞掉异常,事务不会回滚
        }
    }
  4. 目标类未交给Spring管理:未被Spring容器管理的Bean,AOP不生效

  5. 数据库引擎不支持事务:如MySQL的MyISAM引擎

  6. 异步方法中调用事务方法@Async会创建新线程,事务上下文不传递

  7. 事务传播行为配置错误 :如PROPAGATION_NOT_SUPPORTED

面试题4:如何查看JDK动态代理生成的类文件?

参考答案

两种方式:

java 复制代码
// 方式1:代码中设置系统属性(必须在生成代理前设置)
System.setProperty("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");

// 方式2:JVM启动参数
// java -Dsun.misc.ProxyGenerator.saveGeneratedFiles=true MyApp

生成的 .class 文件保存在当前工作目录下的 com/sun/proxy/ 中。

查看方式:

bash 复制代码
# 反汇编查看
javap -c com.sun.proxy.$Proxy0

# 反编译查看
javap -p com.sun.proxy.$Proxy0

# 使用IDEA或JD-GUI查看反编译代码

CGLIB查看生成类

java 复制代码
// 设置系统属性
System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, 
    "/path/to/output");

面试题5:Proxy.newProxyInstance的类加载器为什么要用目标类的类加载器?

参考答案

因为代理类需要:

  1. 加载目标接口:代理类要实现这些接口
  2. 类加载器兼容性:接口的类加载器必须与代理类的类加载器兼容

使用目标类加载器的原因:

  • 目标类加载器已经加载了目标类,大概率也能加载接口
  • 避免 ClassNotFoundException
  • 避免 ClassCastException(不同类加载器加载的同一类不兼容)

在复杂类加载环境(如OSGi、Tomcat)中,类加载器选择错误会导致:

复制代码
java.lang.ClassCastException: 
  com.sun.proxy.$Proxy0 cannot be cast to UserService

面试题6:CGLIB为什么不能代理final类?

参考答案

CGLIB通过生成目标类的子类来实现代理:

java 复制代码
public class OrderService$$EnhancerByCGLIB extends OrderService {
    // 重写方法并添加拦截逻辑
}

Java语言规范规定:

  • final 类不能被继承
  • final 方法不能被重写

因此:

  • final类 → CGLIB无法生成子类 → 无法代理
  • final方法 → CGLIB无法重写 → 方法不被拦截

解决方案

  • 需要代理的类不要声明为final
  • 需要代理的方法不要声明为final
  • 如果必须使用final类,考虑JDK代理(基于接口)或AspectJ

面试题7:JDK动态代理和CGLIB在Spring中的选择策略是什么?

参考答案

Spring AOP的选择策略

复制代码
Spring AOP代理选择逻辑:

目标类有接口?
├── 是 → 使用JDK动态代理(默认)
│         └── 代理接口方法
│         └── 注入时按接口类型注入
│
└── 否 → 使用CGLIB代理
          └── 生成目标类的子类
          └── 可以按类类型注入

Spring Boot 2.x+ 默认行为变更:
- 默认使用CGLIB(spring.aop.proxy-target-class=true)
- 原因:
  1. JDK代理只能代理接口,按类型注入可能失败
  2. CGLIB代理类,注入更灵活
  3. CGLIB性能更好

强制使用JDK代理:
@SpringBootApplication
@EnableAspectJAutoProxy(proxyTargetClass = false)
public class Application { }

强制使用CGLIB:
@EnableAspectJAutoProxy(proxyTargetClass = true)

面试题8:动态代理和反射的关系是什么?

参考答案

复制代码
动态代理 vs 反射:

反射(Reflection):
├── Java运行时检查/修改类和对象行为的能力
├── 核心类:Class、Method、Field、Constructor
├── 用途:动态调用方法、访问字段、创建实例
└── 性能开销大(绕过编译时检查)

动态代理(Dynamic Proxy):
├── 运行时生成代理类的技术
├── 两种实现:JDK Proxy、CGLIB
├── JDK代理依赖反射调用目标方法
└── CGLIB通过FastClass避免反射

关系:
- JDK动态代理底层使用反射调用目标方法
- CGLIB代理底层使用字节码技术,不依赖反射
- 反射是"能力",动态代理是"应用"

面试题9:为什么CGLIB有两个类(Enhancer和FastClass)?

参考答案

CGLIB生成两个类的分工:

复制代码
代理类(*$$EnhancerByCGLIB):
├── 继承目标类
├── 重写方法,插入拦截逻辑
├── 持有MethodInterceptor回调
└── 负责"拦截"

FastClass(*$$FastClassByCGLIB):
├── 不继承目标类
├── 为每个方法分配索引
├── 通过switch(index)直接调用方法
└── 负责"高效调用"

为什么分离?
1. 职责分离:代理类负责AOP逻辑,FastClass负责高效调用
2. 性能优化:FastClass可被复用(如invokeSuper时)
3. 灵活性:可以只生成FastClass而不生成代理(如方法调用优化)

面试题10:手写一个极简的JDK动态代理实现

参考答案

java 复制代码
import java.lang.reflect.*;

/**
 * 极简JDK动态代理实现(模拟核心逻辑)
 */
public class MiniProxy {
    
    /**
     * 模拟Proxy.newProxyInstance
     */
    @SuppressWarnings("unchecked")
    public static <T> T newProxyInstance(ClassLoader loader,
                                          Class<?>[] interfaces,
                                          InvocationHandler h) {
        // 实际实现会生成字节码,这里用反射模拟
        // 真实实现:生成$Proxy0类并加载
        
        // 简化的模拟实现(仅用于理解原理)
        return (T) java.lang.reflect.Proxy.newProxyInstance(
            loader, interfaces, h);
    }
    
    /**
     * 模拟InvocationHandler
     */
    public interface InvocationHandler {
        Object invoke(Object proxy, Method method, Object[] args) throws Throwable;
    }
    
    /**
     * 模拟生成的代理类结构(伪代码)
     */
    /*
    public final class $Proxy0 extends Proxy implements UserService {
        private static Method m1; // saveUser方法
        
        static {
            m1 = UserService.class.getMethod("saveUser", String.class);
        }
        
        public $Proxy0(InvocationHandler h) {
            super(h);
        }
        
        public void saveUser(String name) {
            try {
                super.h.invoke(this, m1, new Object[]{name});
            } catch (Throwable e) {
                throw new UndeclaredThrowableException(e);
            }
        }
    }
    */
    
    // 测试
    public static void main(String[] args) {
        UserService target = new UserServiceImpl();
        
        UserService proxy = newProxyInstance(
            target.getClass().getClassLoader(),
            new Class<?>[]{UserService.class},
            (proxyObj, method, methodArgs) -> {
                System.out.println("[代理] 调用: " + method.getName());
                return method.invoke(target, methodArgs);
            }
        );
        
        proxy.saveUser("测试用户");
    }
}

interface UserService {
    void saveUser(String name);
}

class UserServiceImpl implements UserService {
    @Override
    public void saveUser(String name) {
        System.out.println("保存用户: " + name);
    }
}

小结

动态代理是Java框架的核心基础设施,理解其原理对掌握Spring AOP、MyBatis、Dubbo等框架至关重要。

核心要点回顾

复制代码
动态代理核心知识图谱:

                    ┌─────────────────┐
                    │   动态代理技术   │
                    └────────┬────────┘
                             │
            ┌────────────────┼────────────────┐
            │                                 │
            ▼                                 ▼
    ┌───────────────┐               ┌───────────────┐
    │  JDK动态代理   │               │  CGLIB代理     │
    │  (基于接口)   │               │  (基于继承)   │
    └───────┬───────┘               └───────┬───────┘
            │                               │
    ┌───────┴───────┐               ┌───────┴───────┐
    │ ProxyGenerator│               │ ASM字节码框架  │
    │ 生成$Proxy0   │               │ 生成子类       │
    │ 反射调用目标   │               │ FastClass优化  │
    └───────────────┘               └───────────────┘
            │                               │
            └───────────────┬───────────────┘
                            │
                            ▼
                    ┌───────────────┐
                    │   应用场景     │
                    │ - Spring AOP  │
                    │ - MyBatis     │
                    │ - Dubbo RPC   │
                    │ - 事务管理    │
                    └───────────────┘

选择建议

场景 推荐方案 原因
目标类有接口 JDK动态代理 Spring默认,无额外依赖
目标类无接口 CGLIB 可代理类方法
追求极致性能 AspectJ 编译时织入,无代理开销
运行时字节码操作 Javassist/ASM 灵活控制字节码生成
简单日志/权限 JDK动态代理 简单够用
复杂AOP场景 CGLIB + Spring AOP 功能完善,生态成熟

注意事项

  1. final类/方法:CGLIB无法代理,优先使用接口
  2. 同类内部调用 :代理会失效,使用AopContext.currentProxy()或拆分类
  3. 类加载器:确保代理类加载器能加载目标接口
  4. 性能敏感场景:考虑AspectJ编译时织入
  5. 调试技巧:设置系统属性保存生成的代理类文件

此文原创,转载请注明出处。

相关推荐
放学后的泡泡2 小时前
提供一个工作流的表设计
java·设计规范
MonkeyKing71552 小时前
iOS 开发 ARC 与 MRC 底层原理及区别
ios·面试
生活真难3 小时前
SpringCloud - 任务调度 - xxl-job-java
java·spring boot·spring cloud
盏灯3 小时前
以前有一个同事说:最讨厌下班提需求又没电脑在身边...
前端·后端·面试
人道领域3 小时前
【黑马点评日记】:用户签到功能详解——从Bitmap入门到避坑指南
java·数据库·redis·后端
梦梦代码精3 小时前
《企业开源商城选型:商业闭环、二次开发与成本平衡》
java·开发语言·低代码·开源·github
狼与自由4 小时前
灰度发布的策略
java
蜡笔小马4 小时前
03.C++设计模式-原型模式
c++·设计模式·原型模式
神仙别闹4 小时前
基于QT(C++)实现线性表的建立、插入、删除、查找等基本操作
java·c++·qt