引言
代理模式(Proxy Pattern)是一种经典的结构型设计模式,其核心思想是通过一个代理对象控制对真实对象的访问,在不修改真实对象的前提下增强其功能。在Java生态中,代理模式的应用极为广泛,从Spring的AOP到RPC框架的服务调用,从日志记录到事务管理,代理模式几乎无处不在。
本文将基于一个完整的代理模式演示项目,从最基础的静态代理开始,逐步深入到自定义InvocationHandler、JDK风格动态代理,最终揭秘JDK原生动态代理的底层实现原理。我们将结合源码、字节码分析和JVM机制,掌握Java代理模式的底层逻辑。
一、代理模式的核心价值与分类
1.1 为什么需要代理?
假设我们有一个业务接口UserService
,其实现类UserServiceImpl
负责核心业务逻辑(如查询用户信息)。随着业务扩展,我们需要在不修改UserServiceImpl
的前提下,增加日志记录、权限校验、事务管理等通用功能。此时有两种选择:
- 直接修改
UserServiceImpl
:违反开闭原则,增加维护成本,尤其当多个类需要相同增强时,代码冗余严重。 - 使用代理对象:通过一个代理类包装真实对象,在调用真实方法前后插入增强逻辑,实现功能解耦。
1.2 代理模式的分类
根据代理对象的创建时机和实现方式,Java代理可分为两大类:
- 静态代理:代理类在编译期手动编写或工具生成,与真实类一一对应。
- 动态代理:代理类在运行期动态生成,支持灵活扩展,是Spring AOP的底层实现方式。
二、静态代理:编译期确定的增强
2.1 静态代理的实现原理
静态代理的核心是代理类与真实类实现同一接口 ,代理类持有真实类的引用,并在调用真实方法前后插入增强逻辑。以代码中的JdkAgentProxyServiceAImpl
和其静态代理ProxyServiceAImpl
为例:
java
// 真实类(目标对象)
public class JdkAgentProxyServiceAImpl implements JdkAgentProxyService {
@Override
public void foo() {
log.debug("[目标对象] 执行 foo()");
}
}
// 静态代理类
public class ProxyServiceAImpl implements JdkAgentProxyService {
private final JdkAgentProxyService target = new JdkAgentProxyServiceAImpl(); // 硬编码目标对象
@Override
public void foo() {
log.info("【静态代理】前置增强");
target.foo(); // 调用真实方法
log.info("【静态代理】后置增强");
}
}
2.2 静态代理的执行流程
当调用new ProxyServiceAImpl().foo()
时,执行流程如下:
- 进入代理类的
foo()
方法; - 执行前置增强逻辑(日志记录);
- 调用真实对象的
foo()
方法; - 执行后置增强逻辑;
- 方法退出。
2.3 静态代理的局限性
- 强耦合性 :代理类需要显式引用真实类(如
new JdkAgentProxyServiceAImpl()
),新增接口时需手动编写新的代理类。 - 维护成本高:每个真实类对应一个代理类,当接口数量增多时,代理类数量呈线性增长。
- 扩展性差:无法动态为不同真实对象组合不同的增强逻辑(如某些对象需要日志,另一些需要权限校验)。
三、自定义InvocationHandler:解耦代理逻辑
3.1 设计思想:将增强逻辑抽象为处理器
为解决静态代理的强耦合问题,我们可以将增强逻辑从代理类中抽离,通过一个通用的InvocationHandler
接口来封装。代理类只需负责调用处理器,而无需关心具体的增强逻辑。
代码中的实现如下:
java
// 自定义InvocationHandler(简化版)
@FunctionalInterface
public interface InvocationHandler {
void invoke() throws Exception;
}
// 代理类(持有处理器)
public class ProxyServiceBImpl implements JdkAgentProxyService {
private final InvocationHandler handler; // 处理器
public ProxyServiceBImpl(InvocationHandler handler) {
this.handler = handler; // 注入处理器
}
@Override
public void foo() {
log.info("【自定义Handler代理】进入方法");
try {
handler.invoke(); // 委托给处理器执行增强
} catch (Exception e) {
throw new RuntimeException(e);
} finally {
log.info("【自定义Handler代理】退出方法");
}
}
}
3.2 使用示例与执行流程
java
// 定义处理器(Lambda表达式实现)
InvocationHandler handler = () -> {
log.info("[自定义Handler] 前置增强");
new JdkAgentProxyServiceAImpl().foo(); // 调用真实对象
log.info("[自定义Handler] 后置增强");
};
// 创建代理并执行
ProxyServiceBImpl proxy = new ProxyServiceBImpl(handler);
proxy.foo();
执行流程:
- 调用代理类的
foo()
方法; - 执行代理类的前置日志;
- 调用
handler.invoke()
; - 在
invoke()
中执行前置增强、真实方法调用、后置增强; - 执行代理类的退出日志。
3.3 优势与不足
- 优势 :通过接口解耦代理逻辑,同一代理类可适配不同真实对象(只需传入不同的
InvocationHandler
)。 - 不足:代理类的创建仍需手动编写,且增强逻辑的执行时机(如前置/后置)被固定在代理类中,无法动态调整。
四、JDK风格动态代理(手动模拟):反射驱动的增强
4.1 JDK动态代理的核心组件
JDK原生动态代理的核心由两个接口/类组成:
java.lang.reflect.InvocationHandler
:定义代理方法的调用逻辑(开发者实现)。java.lang.reflect.Proxy
:动态生成代理类的工具类。
与自定义InvocationHandler
不同,JDK的InvocationHandler
接口支持传递方法对象、参数和代理对象本身,提供了更灵活的增强能力。
4.2 手动模拟JDK动态代理的实现
代码中的ProxyServiceCImpl
和ProxyServiceDImpl
演示了手动模拟JDK动态代理的过程。以ProxyServiceCImpl
为例:
java
// JDK风格InvocationHandler(标准版)
@FunctionalInterface
public interface InvocationHandlerB {
Object invoke(Method method, Object[] args) throws Throwable;
}
// 代理类(手动模拟)
public class ProxyServiceCImpl implements JdkAgentProxyBService {
private final InvocationHandlerB handler;
public ProxyServiceCImpl(InvocationHandlerB handler) {
this.handler = handler;
}
@Override
public void foo() throws Throwable {
log.info("【JDK风格代理】进入方法");
try {
// 手动获取方法对象(模拟JDK动态代理的方法解析)
Method targetMethod = JdkAgentProxyBService.class.getMethod("foo");
// 调用处理器处理方法调用
handler.invoke(targetMethod, new Object[0]); // 传递方法、参数
} finally {
log.info("【JDK风格代理】退出方法");
}
}
}
4.3 关键步骤解析
- 方法获取 :通过
Class.getMethod("foo")
手动获取目标方法对象(JDK动态代理会在运行时自动完成此步骤)。 - 处理器调用 :将方法对象和参数传递给
InvocationHandlerB.invoke()
,由开发者实现具体的增强逻辑(如反射调用真实对象)。
4.4 执行流程与局限性
执行proxyC.foo()
时:
- 代理类
foo()
方法被调用; - 获取
foo()
方法对象; - 调用
handler.invoke(method, args)
; - 处理器中通过
method.invoke(realObject, args)
反射调用真实方法。
局限性 :手动模拟需要开发者处理方法获取、参数传递等细节,容易出错(如方法不存在时会抛出NoSuchMethodException
)。JDK原生实现通过字节码生成自动解决了这些问题。
五、JDK原生动态代理:运行时字节码生成
5.1 核心原理:动态生成代理类
JDK原生动态代理的核心是Proxy.newProxyInstance
方法,其作用是在运行时动态生成一个实现了目标接口的代理类,并将该类加载到JVM中。生成的代理类会:
- 继承
java.lang.reflect.Proxy
(注意:Proxy
是final
类,因此代理类无法被继承); - 实现所有目标接口;
- 持有一个
InvocationHandler
实例(通过构造函数注入)。
5.2 代理类的字节码结构
通过javap -v
反编译Proxy.newProxyInstance
生成的代理类(以$Proxy0
为例),可以看到以下关键结构:
java
public final class $Proxy0 extends Proxy implements JdkAgentProxyCService {
private static Method m1; // 对应bar()方法
public $Proxy0(InvocationHandler h) {
super(h); // 调用父类Proxy的构造函数,保存InvocationHandler
}
@Override
public int bar() throws Throwable {
try {
// 调用InvocationHandler的invoke方法,传递代理对象、方法对象、参数
return (int) super.h.invoke(this, m1, null);
} catch (InvocationTargetException | IllegalAccessException e) {
throw e.getCause();
}
}
}
5.3 方法调用的完整流程
当调用代理对象的bar()
方法时,JVM会执行以下步骤:
- 方法分发 :代理类的
bar()
方法被调用,由于代理类继承自Proxy
,且Proxy
的invoke
方法是final
的,实际逻辑会跳转到h.invoke(this, m1, null)
。 - InvocationHandler处理 :开发者实现的
InvocationHandler.invoke(proxy, method, args)
被调用,这里可以添加前置增强(如日志)、通过反射调用真实对象的方法,或添加后置增强。 - 反射调用真实对象 :
method.invoke(realObject, args)
通过反射调用真实对象的bar()
方法。 - 结果返回:真实方法的返回值被包装后返回给代理对象,代理对象将其返回给调用者。
5.4 关键源码分析(Proxy类)
Proxy
类的核心方法包括:
-
newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
:生成代理类的入口方法。- 步骤1 :检查
interfaces
是否合法(非空、非重复)。 - 步骤2 :生成代理类的字节码(通过
ProxyGenerator.generateProxyClass
)。 - 步骤3 :通过
ClassLoader
将字节码加载到JVM,生成Class
对象。 - 步骤4 :通过反射调用代理类的构造函数(参数为
InvocationHandler
),创建代理实例。
- 步骤1 :检查
-
invoke(Object proxy, Method method, Object[] args)
:Proxy
的final
方法,负责将方法调用转发给InvocationHandler
。
5.5 动态代理的性能优化
早期版本中,反射调用的性能较差(约为直接调用的10-100倍)。但从JDK 7开始,JVM引入了MethodHandle
和LambdaMetafactory
,JDK 8的invokedynamic
指令进一步优化了反射性能。现代JVM中,动态代理的性能已接近直接调用(差距在10%以内)。
六、实战对比:不同代理方式的选择
代理类型 | 实现复杂度 | 灵活性 | 性能 | 适用场景 |
---|---|---|---|---|
静态代理 | 低(手动编写) | 低 | 高 | 简单场景、固定增强逻辑 |
自定义InvocationHandler | 中(需定义接口) | 中 | 高 | 小规模扩展、需要解耦增强逻辑 |
JDK风格动态代理(手动模拟) | 高(需处理反射细节) | 高 | 中 | 学习原理、轻量级扩展 |
JDK原生动态代理 | 低(API调用) | 极高 | 高 | 企业级AOP、通用增强场景 |
七、总结与扩展
7.1 核心结论
- 静态代理是动态代理的基础,但扩展性差;
- 自定义
InvocationHandler
通过接口解耦增强了灵活性; - JDK原生动态代理通过运行时字节码生成,实现了高度灵活的通用增强;
- 动态代理的底层依赖反射和字节码生成,理解这些机制有助于解决实际开发中的问题(如代理类无法注入Spring Bean、性能调优等)。
7.2 扩展思考
- Spring AOP的选择:Spring默认使用JDK动态代理(当目标类实现接口时),否则使用CGLIB(基于类继承)。为什么?因为接口代理更符合面向接口编程的原则,而CGLIB通过继承实现,适用于无接口的类。
- 字节码增强技术:除了动态代理,Byte Buddy、ASM等工具也可用于生成字节码,实现更复杂的AOP功能(如方法级别的性能监控)。
- 代理的代理 :多层代理(如AOP中的事务代理嵌套日志代理)的执行顺序是如何控制的?答案是通过
InvocationHandler
的链式调用实现的。
完整代码
java
package com.dwl.jdk_agent_proxy;
import com.dwl.event.Env;
import lombok.extern.slf4j.Slf4j;
import java.io.IOException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* @ClassName JdkAgentProxyCase
* @Description JDK动态代理案例演示类
* 演示不同类型的代理模式实现及底层原理:
* 1. 静态代理
* 2. 自定义InvocationHandler代理
* 3. JDK风格动态代理(手动模拟)
* 4. JDK原生动态代理(Proxy.newProxyInstance)
* @Version 1.0.0
* @Date 2025
* @Author By Dwl
*/
@Slf4j
public class JdkAgentProxyCase {
/**
* 基础服务接口A(无异常声明)
*/
interface JdkAgentProxyService {
void foo();
}
/**
* 扩展服务接口B(含异常声明)
*/
interface JdkAgentProxyBService {
void foo() throws Throwable;
void bar() throws Exception;
}
/**
* 扩展服务接口C(含返回值)
*/
interface JdkAgentProxyCService {
int bar() throws Throwable;
}
// ====================== 被代理的目标类 ======================
/**
* 接口A的基础实现类(目标对象)
*/
static class JdkAgentProxyServiceAImpl implements JdkAgentProxyService {
@Override
public void foo() {
log.debug("[目标对象] JdkAgentProxyServiceAImpl 执行 foo()");
}
}
/**
* 接口B的基础实现类(目标对象)
*/
static class JdkAgentProxyServiceBImpl implements JdkAgentProxyBService {
@Override
public void foo() {
log.debug("[目标对象] JdkAgentProxyServiceBImpl 执行 foo()");
}
@Override
public void bar() {
log.debug("[目标对象] JdkAgentProxyServiceBImpl 执行 bar()");
}
}
/**
* 接口C的基础实现类(目标对象)
*/
static class JdkAgentProxyServiceCImpl implements JdkAgentProxyCService {
@Override
public int bar() {
log.debug("[目标对象] JdkAgentProxyServiceCImpl 执行 bar()");
return Integer.MAX_VALUE;
}
}
// ====================== 静态代理实现 ======================
/**
* 静态代理类(针对接口A)
* 特点:代理类与被代理类实现同一接口,手动编写增强逻辑
*/
static class ProxyServiceAImpl implements JdkAgentProxyService {
// 目标对象(硬编码,静态代理的局限性)
private final JdkAgentProxyService target = new JdkAgentProxyServiceAImpl();
@Override
public void foo() {
log.info("【静态代理】进入 ProxyServiceAImpl.foo() 方法");
try {
// 前置增强逻辑
log.info("【静态代理】前置增强:准备执行目标方法");
// 调用目标对象方法
target.foo();
// 后置增强逻辑
log.info("【静态代理】后置增强:目标方法执行完成");
} finally {
log.info("【静态代理】退出 ProxyServiceAImpl.foo() 方法");
}
}
}
// ====================== 自定义InvocationHandler代理 ======================
/**
* 自定义InvocationHandler接口(简化版)
*/
@FunctionalInterface
interface InvocationHandler {
void invoke() throws Exception;
}
/**
* 自定义代理类(针对接口A)
* 特点:通过接口解耦代理逻辑,支持动态注入处理器
*/
static class ProxyServiceBImpl implements JdkAgentProxyService {
private final InvocationHandler handler; // 方法调用处理器
public ProxyServiceBImpl(InvocationHandler handler) {
this.handler = handler;
}
@Override
public void foo() {
log.info("【自定义Handler代理】进入 ProxyServiceBImpl.foo() 方法");
try {
handler.invoke(); // 委托给处理器执行
} catch (Exception e) {
throw new RuntimeException(e);
} finally {
log.info("【自定义Handler代理】退出 ProxyServiceBImpl.foo() 方法");
}
}
}
// ====================== JDK风格动态代理(手动模拟) ======================
/**
* JDK风格InvocationHandler接口(标准版)
* 对应JDK的java.lang.reflect.InvocationHandler
*/
@FunctionalInterface
interface InvocationHandlerB {
void invoke(Method method, Object[] args) throws Throwable;
}
/**
* JDK风格动态代理类(针对接口B)
* 模拟JDK动态代理的核心逻辑:通过反射调用目标方法
*/
static class ProxyServiceCImpl implements JdkAgentProxyBService {
private final InvocationHandlerB handler; // JDK风格处理器
public ProxyServiceCImpl(InvocationHandlerB handler) {
this.handler = handler;
}
@Override
public void foo() throws Throwable {
log.info("【JDK风格代理】进入 ProxyServiceCImpl.foo() 方法");
try {
// 手动获取方法对象(模拟JDK动态代理的方法解析)
Method targetMethod = JdkAgentProxyBService.class.getMethod("foo");
// 调用处理器处理方法调用
handler.invoke(targetMethod, new Object[0]);
} finally {
log.info("【JDK风格代理】退出 ProxyServiceCImpl.foo() 方法");
}
}
@Override
public void bar() {
log.info("【JDK风格代理】进入 ProxyServiceCImpl.bar() 方法");
try {
Method targetMethod = JdkAgentProxyBService.class.getMethod("bar");
handler.invoke(targetMethod, new Object[0]);
} catch (Throwable e) {
throw new RuntimeException(e);
} finally {
log.info("【JDK风格代理】退出 ProxyServiceCImpl.bar() 方法");
}
}
}
/**
* JDK风格动态代理类(针对接口C,带返回值)
*/
static class ProxyServiceDImpl implements JdkAgentProxyCService {
private final InvocationHandlerC handler;
public ProxyServiceDImpl(InvocationHandlerC handler) {
this.handler = handler;
}
@Override
public int bar() throws Throwable {
log.info("【JDK风格代理】进入 ProxyServiceDImpl.bar() 方法");
try {
Method targetMethod = JdkAgentProxyServiceCImpl.class.getMethod("bar");
return (int) handler.invoke(targetMethod, new Object[0]);
} finally {
log.info("【JDK风格代理】退出 ProxyServiceDImpl.bar() 方法");
}
}
}
/**
* JDK风格InvocationHandler接口(支持目标对象传递)
*/
@FunctionalInterface
interface InvocationHandlerC {
Object invoke(Method method, Object[] args) throws Throwable;
}
/**
* JDK风格动态代理类(支持通过this传递代理对象)
*/
static class ProxyServiceEImpl implements JdkAgentProxyCService {
private final InvocationHandlerD handler;
private static final Method BAR_METHOD; // 缓存方法对象(提升性能)
static {
try {
BAR_METHOD = JdkAgentProxyServiceCImpl.class.getMethod("bar");
} catch (NoSuchMethodException e) {
throw new RuntimeException("方法获取失败", e);
}
}
public ProxyServiceEImpl(InvocationHandlerD handler) {
this.handler = handler;
}
@Override
public int bar() {
log.info("【JDK风格代理】进入 ProxyServiceEImpl.bar() 方法");
try {
// 传递代理对象本身(类似JDK动态代理的this引用)
return (int) handler.invoke(this, BAR_METHOD, new Object[0]);
} catch (Throwable e) {
throw new RuntimeException(e);
} finally {
log.info("【JDK风格代理】退出 ProxyServiceEImpl.bar() 方法");
}
}
}
/**
* JDK风格InvocationHandler接口(标准JDK参数形式)
*/
@FunctionalInterface
interface InvocationHandlerD {
Object invoke(Object proxy, Method method, Object[] args) throws Throwable;
}
// ====================== JDK原生动态代理 ======================
/**
* JDK原生动态代理类(通过Proxy.newProxyInstance生成)
* 注意:实际开发中不需要手动继承Proxy,此处为演示原理手动实现
*/
static class ProxyServiceFImpl extends Proxy implements JdkAgentProxyCService {
private static final Method BAR_METHOD; // 缓存方法对象
static {
try {
BAR_METHOD = JdkAgentProxyServiceCImpl.class.getMethod("bar");
} catch (NoSuchMethodException e) {
throw new RuntimeException("方法获取失败", e);
}
}
// 实际持有的InvocationHandler(JDK动态代理核心)
private final java.lang.reflect.InvocationHandler h;
public ProxyServiceFImpl(java.lang.reflect.InvocationHandler handler) {
super(handler);
this.h = handler;
}
@Override
public int bar() throws Throwable {
log.info("【JDK原生代理】进入 ProxyServiceFImpl.bar() 方法");
try {
// 调用InvocationHandler的invoke方法(JDK核心逻辑)
return (int) h.invoke(this, BAR_METHOD, new Object[0]);
} finally {
log.info("【JDK原生代理】退出 ProxyServiceFImpl.bar() 方法");
}
}
}
/**
* 主方法:演示各种代理模式的执行流程
*/
public static void main(String[] args) throws IOException {
log.info("===== 开始测试静态代理 =====");
new ProxyServiceAImpl().foo();
log.info("\n===== 开始测试自定义InvocationHandler代理 =====");
testCustomInvocationHandler();
log.info("\n===== 开始测试JDK风格动态代理(手动模拟) =====");
testJdkStyleProxy();
log.info("\n===== 开始测试JDK原生动态代理 =====");
testJdkNativeProxy();
Env.sleep(10000); // 保持进程运行以便观察
}
/**
* 测试自定义InvocationHandler代理
*/
private static void testCustomInvocationHandler() {
// 定义处理器逻辑(Lambda表达式实现InvocationHandler)
InvocationHandler handler = () -> {
log.info("[自定义Handler] 前置增强:准备执行目标方法");
new JdkAgentProxyServiceAImpl().foo(); // 调用目标对象方法
log.info("[自定义Handler] 后置增强:目标方法执行完成");
};
// 创建代理实例并执行方法
ProxyServiceBImpl proxy = new ProxyServiceBImpl(handler);
proxy.foo();
}
/**
* 测试JDK风格动态代理(手动模拟)
*/
private static void testJdkStyleProxy() {
// 1. 定义JDK风格处理器(模拟JDK动态代理的InvocationHandler)
InvocationHandlerB jdkStyleHandler = (method, argsArray) -> {
log.info("[JDK Handler] 前置增强:准备执行方法 - {}", method.getName());
// 反射调用目标对象方法(目标对象为JdkAgentProxyServiceBImpl实例)
return method.invoke(new JdkAgentProxyServiceBImpl(), argsArray);
};
// 2. 创建代理实例并测试方法
ProxyServiceCImpl proxyC = new ProxyServiceCImpl(jdkStyleHandler);
try {
proxyC.foo();
proxyC.bar();
} catch (Exception e) {
log.error("JDK风格代理执行异常", e);
} catch (Throwable e) {
throw new RuntimeException(e);
}
// 3. 测试带返回值的代理(接口C)
InvocationHandlerC handlerC = (method, argsArray) -> {
log.info("[JDK Handler] 前置增强:准备执行方法 - {}", method.getName());
return method.invoke(new JdkAgentProxyServiceCImpl(), argsArray);
};
ProxyServiceDImpl serviceD = new ProxyServiceDImpl(handlerC);
try {
log.info("【JDK风格代理】bar() 返回值:{}", serviceD.bar());
} catch (Exception e) {
log.error("JDK风格代理bar()执行异常", e);
} catch (Throwable e) {
throw new RuntimeException(e);
}
// 4. 测试传递代理对象的处理器
InvocationHandlerD handlerD = (proxy, method, argsArray) -> {
log.info("[JDK Handler] 前置增强:准备执行方法 - {}", method.getName());
return method.invoke(new JdkAgentProxyServiceCImpl(), argsArray);
};
ProxyServiceEImpl serviceE = new ProxyServiceEImpl(handlerD);
try {
log.info("【JDK风格代理】bar() 返回值:{}", serviceE.bar());
} catch (Exception e) {
log.error("JDK风格代理bar()执行异常", e);
}
}
/**
* 测试JDK原生动态代理
*/
private static void testJdkNativeProxy() {
// 使用Proxy.newProxyInstance创建原生动态代理
JdkAgentProxyCService serviceF = (JdkAgentProxyCService) Proxy.newProxyInstance(
JdkAgentProxyCase.class.getClassLoader(), // 类加载器
new Class<?>[]{JdkAgentProxyCService.class}, // 代理需要实现的接口
(proxy, method, argsArray) -> { // InvocationHandler实现
log.info("[JDK原生Handler] 前置增强:准备执行方法 - {}", method.getName());
// 反射调用目标对象方法(目标对象为JdkAgentProxyServiceCImpl实例)
return method.invoke(new JdkAgentProxyServiceCImpl(), argsArray);
}
);
// 执行代理方法
try {
log.info("【JDK原生代理】bar() 返回值:{}", serviceF.bar());
} catch (Throwable e) {
log.error("JDK原生代理bar()执行异常", e);
}
// 输出代理类信息(调试用)
log.info("【JDK原生代理】代理类信息:{}", serviceF.getClass());
}
}