深度揭秘:Objenesis 如何劫持 ReflectionFactory 实现 2.5 倍提速的无构造器实例化
【免费下载链接】objenesisOkay, it's pretty easy to instantiate objects in Java through standard reflection. However there are many cases where you need to go beyond what reflection provides. For example, if there's no public constructor, you want to bypass the constructor code, or set final fields. There are numerous clever (but fiddly) approaches to getting around this and this library provides a simple way to get at them. You will find the official site here.项目地址: https://gitcode.com/gh_mirrors/ob/objenesis
Objenesis是一个专门用于"无构造器实例化"(bypass the constructor)的 Java 开源工具:当类没有公开构造器、或你想完全跳过构造器代码直接拿到一个对象时,它能用几行配置搞定各种高深且琐碎的黑科技。在最常见的 HotSpot/OpenJDK 平台上,Objenesis 通过"劫持"JDK 内部的 ReflectionFactory 工厂,拿到一个专门跳过构造器的"魔改构造器",实测比同样绕开构造器的 Unsafe 方案快约 2.5 倍。
🤔 为什么需要"无构造器实例化"?
Java 标准反射能创建对象,但绕不开几个硬伤:
| 场景 | 标准反射的困境 |
|---|---|
| 只有私有/受保护构造器 | 需要反射 hack + setAccessible,还要构造参数 |
| 构造器会抛异常或依赖外部环境(数据库、网络) | 一执行就炸,Mock 框架根本无法测试 |
| 序列化/反序列化 | 必须跳过构造器,直接"摆出"一个内存对象 |
这正是 Mock 测试框架(如 EasyMock)和序列化库依赖 Objenesis 的原因——它们需要"凭空出现"一个对象,而构造器一个字节都不许执行。
🧭 策略路由:Objenesis 怎么为你选对"劫持"方式
Objenesis 的入口类 ObjenesisStd.java 背后是一套"策略模式"路由:默认策略 StdInstantiatorStrategy.java 读取 PlatformDescription.java 里缓存的 JVM 名称与版本,为当前平台挑选最优的ObjectInstantiator:
- HotSpot / OpenJDK→
SunReflectionFactoryInstantiator(ReflectionFactory 魔改构造器方案,默认之选) - Dalvik(Android)→ 按 API 级别分发
Android10/17/18Instantiator;Android N 以后的 OpenJDK 版走UnsafeFactoryInstantiator - GNU GCJ / PERC→ 各自的专用实现
- 兜底→
UnsafeFactoryInstantiator,几乎所有现代 JVM 都能用
🔧 核心揭秘:ReflectionFactory 的"劫持"三步曲
HotSpot 的sun.reflect.ReflectionFactory提供了一个公开 API:newConstructorForSerialization(类, 替换构造器)。它本是 Java 序列化的"内部管道"——反序列化时 JVM 需要跳过构造器直接摆内存,HotSpot 为此制造了一个魔改构造器(munged constructor):调用它只分配内存并把字段初始化为零,用户的构造器一行代码都不执行。
Objenesis 的 SunReflectionFactoryInstantiator.java 直接"蹭"上这条管道,整个流程只有三步:
- 通过反射拿到全局单例
ReflectionFactory.getReflectionFactory(); - 取出
newConstructorForSerialization方法; - 以目标类 +
Object的空构造器为参数调用它,得到一个mungedConstructor,之后newInstance()就是纯粹的内存分配。
兼容性问题由 SunReflectionFactoryHelper.java 收编:先尝试加载sun.reflect.ReflectionFactory,找不到再降级到jdk.internal.reflect.ReflectionFactory(Java 9+ 模块系统的"新官方"版本);两者都失败时抛出一个带--add-modules jdk.unsupported提示的友好异常。
🏎️ 2.5 倍提速是怎么来的?基准测试数据说话
同样跳过构造器,为什么不用更简单的Unsafe.allocateInstance?源码注释写得很直白:"基准测试显示它慢 2.5 倍,所以我更爱这个"。官方基准(Benchmarks.md,测试代码见 CreateObject.java)在 HotSpot 上对Object的实测结果:
| 实例化方式 | 平均耗时 | 单位 |
|---|---|---|
默认构造器new Object() | 3,509,724 | nsec/op |
| ReflectionFactory 魔改构造器 | 6,995 | nsec/op |
| Unsafe.allocateInstance | 20,382 | nsec/op |
对比非常清晰:魔改构造器方案比 Unsafe 快约 2.9 倍(官方保守表述为 2.5 倍)。
更关键的第二组数据来自ConcurrentGetInstantiator基准——缓存的价值:ObjenesisBase.java 默认使用ClassValue按类缓存实例器,取一次实例器的平均耗时:
| 缓存策略 | 平均耗时 | 单位 |
|---|---|---|
| 并发集合缓存(Java 5 方案) | 238.9 | nsec/op |
| 无缓存(每次重新查找工厂) | 5,253,937 | nsec/op |
不缓存的话,取实例器比带缓存慢 2 万多倍。所以 Objenesis 默认永远带缓存,且实例器线程安全,可放心复用。
📦 全平台适配与 Java 9+ 注意事项
Objenesis 对主流 JVM 都有覆盖,详见 SupportedJVMs.md:Sun/Oracle HotSpot 1.3–18、OpenJDK 6–18、Android API 8–30、Azul Zulu/Zing、IKVM、GCJ、PERC 等。此外还有一个可选的objenesis-exotic模块(exotic/),提供MagicInstantiator(动态定义"魔法类"字节码)和ProxyingInstantiator等更极端的方案;主包中的同名类(如 MagicInstantiator.java)只是薄壳,通过 DelegatingToExoticInstantiator.java 委托过去,只在 classpath 中引入 exotic 模块时才可用。
Java 9 及以后如果模块系统拦截了内部 API,JVM 启动时加上--add-modules jdk.unsupported即可,Objenesis 的异常信息也会主动提醒你。
⚡ 快速上手:3 行代码完成无构造器实例化
安装依赖后,最简用法就是:
import org.objenesis.ObjenesisStd; ObjenesisStd objenesis = new ObjenesisStd(); MyClass instance = objenesis.newInstance(MyClass.class); // 对象已创建,构造器 0 字节执行,字段全为零值想批量创建同一类实例时,先调用objenesis.getInstantiatorOf(clazz)拿到并缓存的实例器再循环newInstance(),效率最高。
一句话总结:Objenesis 把"绕过构造器"这件各 JVM 上五花八门的黑科技,收敛成了一次策略路由 + 一个魔改构造器——而它在 HotSpot 上选择 ReflectionFactory 而非 Unsafe 的决策,正是那 2.5 倍提速的由来。
【免费下载链接】objenesisOkay, it's pretty easy to instantiate objects in Java through standard reflection. However there are many cases where you need to go beyond what reflection provides. For example, if there's no public constructor, you want to bypass the constructor code, or set final fields. There are numerous clever (but fiddly) approaches to getting around this and this library provides a simple way to get at them. You will find the official site here.项目地址: https://gitcode.com/gh_mirrors/ob/objenesis
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考