package UnSafe;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
public class UnsafeUtil {
private static final Object UNSAFE;
private static final Method ALLOCATE_INSTANCE;
static {
try {
// 1. 通过反射加载 sun.misc.Unsafe 类
Class<?> unsafeClass = Class.forName("sun.misc.Unsafe");
// 2. 获取 Unsafe 类中名为 "theUnsafe" 的私有静态字段
Field field = unsafeClass.getDeclaredField("theUnsafe");
// 3. 绕过 Java 的访问控制检查,使其可以访问
field.setAccessible(true);
// 4. 获取该字段的值。由于它是静态的,传入 null 作为对象参数
UNSAFE = field.get(null);
// 5. 缓存 allocateInstance 方法
ALLOCATE_INSTANCE = unsafeClass.getDeclaredMethod("allocateInstance", Class.class);
ALLOCATE_INSTANCE.setAccessible(true);
} catch (ClassNotFoundException | NoSuchFieldException | NoSuchMethodException | IllegalAccessException e) {
throw new RuntimeException("无法获取 Unsafe 实例", e);
}
}
public static Object getUnsafe() {
return UNSAFE;
}
@SuppressWarnings("unchecked")
public static <T> T allocateInstance(Class<T> clazz) throws InstantiationException {
try {
return (T) ALLOCATE_INSTANCE.invoke(UNSAFE, clazz);
} catch (Exception e) {
throw new InstantiationException(e.getMessage());
}
}
}
package UnSafe;
public class YourFrameworkClass {
public static <T> T createInstanceWithoutConstructor(Class<T> clazz) throws InstantiationException {
// 注意:allocateInstance 本身声明了 InstantiationException
// 但如果传入的是接口、抽象类、数组或原始类型,会抛出异常
return UnsafeUtil.allocateInstance(clazz);
}
// 使用示例
public static void main(String[] args) throws Exception {
// 假设有一个类,其构造器可能很重,或私有的,或有副作用
class MyClass {
private int value = 10; // 字段会被初始化为默认值 0,而非 10
public MyClass() {
System.out.println("构造器被调用");
this.value = 20;
}
public int getValue() { return value; }
}
// 常规方式:构造器被调用,输出 "构造器被调用",value 为 20
MyClass normal = new MyClass();
System.out.println(normal.getValue()); // 输出 20
// Unsafe 方式:构造器未被调用,value 被 JVM 零值初始化为 0
MyClass unsafeInstance = createInstanceWithoutConstructor(MyClass.class);
System.out.println(unsafeInstance.getValue()); // 输出 0
}
}
package UnSafe;
import java.lang.reflect.Field;
/**
* 演示使用 Unsafe 解决循环依赖问题
*
* 场景:A 依赖 B,B 依赖 A,形成循环依赖
* 传统方式:new A(new B(new A(...))) 无法完成
* Unsafe 方式:先创建空壳对象,再注入依赖
*/
public class CircularDependencyDemo {
// ========== 1. 定义循环依赖的类 ==========
static class ServiceA {
private ServiceB serviceB;
private String name = "ServiceA";
public ServiceA(ServiceB serviceB) {
this.serviceB = serviceB;
System.out.println("ServiceA 构造器被调用");
}
public void doSomething() {
System.out.println(name + " 调用 " + serviceB.getName());
}
public String getName() {
return name;
}
public ServiceB getServiceB() {
return serviceB;
}
}
static class ServiceB {
private ServiceA serviceA;
private String name = "ServiceB";
public ServiceB(ServiceA serviceA) {
this.serviceA = serviceA;
System.out.println("ServiceB 构造器被调用");
}
public void doSomething() {
System.out.println(name + " 调用 " + serviceA.getName());
}
public String getName() {
return name;
}
public ServiceA getServiceA() {
return serviceA;
}
}
// ========== 2. 循环依赖解决器 ==========
static class CircularDependencyResolver {
/**
* 解决 A 和 B 的循环依赖
* 核心思路:
* 1. 用 Unsafe 创建空壳对象(跳过构造器)
* 2. 通过反射注入依赖字段
*/
public static Object[] resolveCircularDependency() throws Exception {
// 第一步:创建空壳对象(不调用构造器)
ServiceA serviceA = UnsafeUtil.allocateInstance(ServiceA.class);
ServiceB serviceB = UnsafeUtil.allocateInstance(ServiceB.class);
System.out.println("✓ 空壳对象创建完成(构造器未被调用)");
System.out.println(" serviceA.name = " + serviceA.getName()); // null(零值)
System.out.println(" serviceB.name = " + serviceB.getName()); // null(零值)
// 第二步:通过反射注入依赖
// 注入 serviceA.serviceB = serviceB
Field fieldB = ServiceA.class.getDeclaredField("serviceB");
fieldB.setAccessible(true);
fieldB.set(serviceA, serviceB);
// 注入 serviceB.serviceA = serviceA
Field fieldA = ServiceB.class.getDeclaredField("serviceA");
fieldA.setAccessible(true);
fieldA.set(serviceB, serviceA);
System.out.println("✓ 依赖注入完成");
// 第三步:手动初始化字段(因为跳过了构造器)
Field nameFieldA = ServiceA.class.getDeclaredField("name");
nameFieldA.setAccessible(true);
nameFieldA.set(serviceA, "ServiceA");
Field nameFieldB = ServiceB.class.getDeclaredField("name");
nameFieldB.setAccessible(true);
nameFieldB.set(serviceB, "ServiceB");
System.out.println("✓ 字段初始化完成");
System.out.println(" serviceA.name = " + serviceA.getName());
System.out.println(" serviceB.name = " + serviceB.getName());
return new Object[]{serviceA, serviceB};
}
}
// ========== 3. 演示 ==========
public static void main(String[] args) throws Exception {
System.out.println("========== 循环依赖问题演示 ==========\n");
// 传统方式:无法解决循环依赖
System.out.println("【传统方式】");
System.out.println("new ServiceA(new ServiceB(new ServiceA(...))) - 无法完成!\n");
// Unsafe 方式:成功解决
System.out.println("【Unsafe 方式】");
Object[] result = CircularDependencyResolver.resolveCircularDependency();
ServiceA serviceA = (ServiceA) result[0];
ServiceB serviceB = (ServiceB) result[1];
System.out.println("\n========== 验证循环依赖已解决 ==========");
// 验证循环引用
System.out.println("serviceA.getServiceB() == serviceB: " + (serviceA.getServiceB() == serviceB));
System.out.println("serviceB.getServiceA() == serviceA: " + (serviceB.getServiceA() == serviceA));
// 验证方法调用
System.out.println("\n========== 验证方法调用 ==========");
serviceA.doSomething(); // ServiceA 调用 ServiceB
serviceB.doSomething(); // ServiceB 调用 ServiceA
System.out.println("\n========== 对比:构造器调用情况 ==========");
System.out.println("注意:构造器从未被调用!");
System.out.println("这就是 Unsafe.allocateInstance() 的威力:");
System.out.println("- 跳过构造器创建对象");
System.out.println("- 允许后续手动注入依赖");
System.out.println("- 从而打破循环依赖的死锁");
}
}

# UnSafe 包说明文档
## 概述
本包演示了 Java 中 `sun.misc.Unsafe` 的使用方式,包括绕过构造器创建对象、解决循环依赖等高级场景。这些技术是 Spring、Netty 等主流框架底层实现的核心原理。
## 文件结构
```
UnSafe/
├── UnsafeUtil.java # Unsafe 工具类(核心)
├── YourFrameworkClass.java # 基础示例:跳过构造器创建对象
├── CircularDependencyDemo.java # 进阶示例:解决循环依赖
└── README.md # 本文档
```
## 核心类说明
### 1. UnsafeUtil — Unsafe 工具类
**作用:** 通过纯反射方式获取 `sun.misc.Unsafe` 实例,兼容 JDK 8 ~ JDK 21+。
**实现原理:**
```
Class.forName("sun.misc.Unsafe") → 获取 theUnsafe 字段 → 缓存 allocateInstance 方法
```
- 不直接 import `sun.misc.Unsafe`,避免编译期模块访问限制
- 通过 `Class.forName()` 动态加载,绕过 JDK 9+ 的模块化封装
- 缓存 `allocateInstance` 方法,避免重复反射开销
**核心 API:**
| 方法 | 说明 |
|------|------|
| `getUnsafe()` | 返回 Unsafe 实例(Object 类型) |
| `allocateInstance(Class<T>)` | 跳过构造器创建对象实例 |
### 2. YourFrameworkClass — 基础示例
**作用:** 演示 `allocateInstance()` 与 `new` 创建对象的区别。
**关键对比:**
| 特性 | `new MyClass()` | `UnsafeUtil.allocateInstance(MyClass.class)` |
|------|-----------------|----------------------------------------------|
| 构造器调用 | 是 | 否 |
| 字段初始化 | 执行字段初始化器 | 全部为零值(null/0/false) |
| 示例中 value 值 | 20 | 0 |
### 3. CircularDependencyDemo — 循环依赖解决示例
**作用:** 演示使用 Unsafe 解决 A ↔ B 循环依赖问题。
**问题场景:**
```
ServiceA 构造器需要 ServiceB
ServiceB 构造器需要 ServiceA
→ new ServiceA(new ServiceB(new ServiceA(...))) 无限递归,无法完成
```
**解决步骤:**
```
第一步:allocateInstance() 创建空壳对象(跳过构造器)
↓
第二步:反射注入依赖字段(建立对象间引用)
↓
第三步:手动初始化其他字段值
```
**流程图:**
```
┌─────────────────────────────────────────────────┐
│ ServiceA a = allocateInstance(ServiceA.class) │ ← 空壳,字段全为 null
│ ServiceB b = allocateInstance(ServiceB.class) │ ← 空壳,字段全为 null
├─────────────────────────────────────────────────┤
│ a.serviceB = b (反射注入) │ ← 建立 A → B 引用
│ b.serviceA = a (反射注入) │ ← 建立 B → A 引用
├─────────────────────────────────────────────────┤
│ a.name = "ServiceA" (手动初始化) │
│ b.name = "ServiceB" (手动初始化) │
├─────────────────────────────────────────────────┤
│ 循环依赖解决完成 ✓ │
│ a.serviceB == b ✓ │
│ b.serviceA == a ✓ │
└─────────────────────────────────────────────────┘
```
## 与 Spring 框架的关系
Spring 解决循环依赖的核心机制与本示例一致:
| 本示例 | Spring 实现 |
|--------|------------|
| `allocateInstance()` 创建空壳 | `Objenesis` 创建早期引用 |
| 反射注入依赖字段 | 属性注入(`populateBean`) |
| 手动初始化字段 | `initializeBean`(调用 `@PostConstruct` 等) |
Spring 使用**三级缓存** + `Objenesis`(底层即 `Unsafe.allocateInstance()`)来处理 Bean 的循环依赖。
## 注意事项
1. **字段零值问题:** `allocateInstance()` 创建的对象所有字段为零值,不会执行字段初始化器和构造器逻辑
2. **安全风险:** Unsafe 操作绕过 Java 访问控制,使用不当可能导致 JVM 崩溃
3. **生产建议:** 生产环境应使用 Spring 等成熟框架,不建议直接操作 Unsafe
4. **JDK 兼容性:** 本实现通过纯反射方式获取 Unsafe,兼容 JDK 8 至 JDK 21+
## 运行方式
```bash
# 编译
mvn compile
# 运行基础示例
mvn exec:java -Dexec.mainClass="UnSafe.YourFrameworkClass"
# 运行循环依赖示例
mvn exec:java -Dexec.mainClass="UnSafe.CircularDependencyDemo"
```
View Code