本文深入讲解 JDK 动态代理CGLIB 动态代理 的区别、实现原理、应用场景,并通过 示例代码详细注释 帮助你彻底掌握这两种代理技术!✨


目录

  1. JDK 动态代理 vs CGLIB 动态代理
  2. JDK 动态代理实现原理
  3. JDK 动态代理示例
  4. 扩展 JDK 动态代理示例
  5. CGLIB 动态代理实现原理
  6. CGLIB 动态代理示例
  7. 总结

1. JDK 动态代理 vs CGLIB 动态代理

核心区别

特性 JDK 动态代理 CGLIB 动态代理
代理对象类型 基于接口 基于类(无需接口)
性能 较慢(反射调用) 较快(字节码生成)
依赖 无需额外依赖 需要引入 CGLIB 库
限制 只能代理实现了接口的类 不能代理 final 类或方法
实现原理 反射 + 动态生成代理类 字节码生成 + 继承

适用场景

  • JDK 动态代理:适用于代理接口或需要轻量级代理的场景。
  • CGLIB 动态代理:适用于代理类或需要高性能代理的场景。

2. JDK 动态代理实现原理

核心机制

  1. 反射调用:通过 java.lang.reflect.Proxy 动态生成代理类。
  2. InvocationHandler:代理类的所有方法调用都会转发到 InvocationHandlerinvoke 方法。
  3. 接口绑定:代理类必须实现目标接口。

优点

  • 无需额外依赖。
  • 轻量级,适合简单场景。

缺点

  • 只能代理接口。
  • 性能较差(反射调用)。

3. JDK 动态代理示例

示例代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

// 1. 定义接口
interface UserService {
void saveUser(String name);
}

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

// 3. 实现 InvocationHandler
class UserServiceProxy implements InvocationHandler {
private final Object target; // 目标对象

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

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

// 4. 创建并使用代理对象
public class JdkProxyDemo {
public static void main(String[] args) {
// 目标对象
UserService target = new UserServiceImpl();

// 创建代理对象
UserService proxy = (UserService) Proxy.newProxyInstance(
target.getClass().getClassLoader(), // 类加载器
target.getClass().getInterfaces(), // 目标接口
new UserServiceProxy(target) // InvocationHandler
);

// 调用代理方法
proxy.saveUser("Alice");
}
}

输出结果

1
2
3
方法调用前: saveUser
保存用户: Alice
方法调用后: saveUser

代码解析

  1. 目标接口UserService 定义了业务方法。
  2. 目标实现类UserServiceImpl 实现了接口。
  3. InvocationHandlerUserServiceProxy 负责拦截方法调用。
  4. 代理对象:通过 Proxy.newProxyInstance 动态生成。

4. 扩展 JDK 动态代理示例

扩展功能

  • 在代理方法前后添加日志记录和性能监控。

示例代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

// 1. 定义接口
interface OrderService {
void createOrder(String orderId);
}

// 2. 实现接口
class OrderServiceImpl implements OrderService {
@Override
public void createOrder(String orderId) {
System.out.println("创建订单: " + orderId);
}
}

// 3. 扩展 InvocationHandler
class OrderServiceProxy implements InvocationHandler {
private final Object target; // 目标对象

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

@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
long startTime = System.currentTimeMillis();
System.out.println("开始执行: " + method.getName());

// 调用目标方法
Object result = method.invoke(target, args);

long endTime = System.currentTimeMillis();
System.out.println("执行完成: " + method.getName() + ", 耗时: " + (endTime - startTime) + "ms");
return result;
}
}

// 4. 创建并使用代理对象
public class ExtendedJdkProxyDemo {
public static void main(String[] args) {
// 目标对象
OrderService target = new OrderServiceImpl();

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

// 调用代理方法
proxy.createOrder("12345");
}
}

输出结果

1
2
3
开始执行: createOrder
创建订单: 12345
执行完成: createOrder, 耗时: 2ms

扩展点

  • 日志记录:在方法调用前后打印日志。
  • 性能监控:记录方法执行时间。

5. CGLIB 动态代理实现原理

核心机制

  1. 字节码生成:通过 ASM 库动态生成目标类的子类。
  2. 方法拦截:通过 MethodInterceptor 拦截方法调用。
  3. 继承机制:代理类继承目标类。

优点

  • 可以代理类(无需接口)。
  • 性能较好(直接调用字节码)。

缺点

  • 不能代理 final 类或方法。
  • 需要引入 CGLIB 依赖。

6. CGLIB 动态代理示例

示例代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

// 1. 目标类(无需接口)
class ProductService {
public void addProduct(String name) {
System.out.println("添加产品: " + name);
}
}

// 2. 实现 MethodInterceptor
class ProductServiceInterceptor implements MethodInterceptor {
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
System.out.println("方法调用前: " + method.getName());
Object result = proxy.invokeSuper(obj, args); // 调用父类方法
System.out.println("方法调用后: " + method.getName());
return result;
}
}

// 3. 创建并使用代理对象
public class CglibProxyDemo {
public static void main(String[] args) {
// 创建 Enhancer 对象
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(ProductService.class); // 设置父类
enhancer.setCallback(new ProductServiceInterceptor()); // 设置回调

// 创建代理对象
ProductService proxy = (ProductService) enhancer.create();

// 调用代理方法
proxy.addProduct("iPhone 15");
}
}

输出结果

1
2
3
方法调用前: addProduct
添加产品: iPhone 15
方法调用后: addProduct

代码解析

  1. 目标类ProductService 定义了业务方法。
  2. MethodInterceptorProductServiceInterceptor 负责拦截方法调用。
  3. 代理对象:通过 Enhancer 动态生成。

7. 总结

核心对比

特性 JDK 动态代理 CGLIB 动态代理
代理对象类型 基于接口 基于类(无需接口)
性能 较慢(反射调用) 较快(字节码生成)
依赖 无需额外依赖 需要引入 CGLIB 库
限制 只能代理实现了接口的类 不能代理 final 类或方法

选择建议

  • 如果目标对象实现了接口,优先使用 JDK 动态代理
  • 如果目标对象没有实现接口,或者需要更高性能,使用 CGLIB 动态代理

通过本文的学习,你已经掌握了 JDK 动态代理和 CGLIB 动态代理的核心原理和实现方法。快去实践吧!🚀