前言
Objenesis是一個小的java庫,主要用來實例化類對象,java本身僅支持通過構造器實例化,實例化時必須使用合適的構造器,但有些情況下不能使用這種方式實例化:
- 構造器需要參數
- 構造器有副作用
- 構造器會拋異常
一些常見的類庫都要求類包含一個默認的無參構造器,而Objenesis可以繞過構造器來實例化對象。
簡單使用
定義一個用來實例化的類,不包含默認構造器
public class User {
private String name;
public User(String name) {
System.out.println("User.Constructor");
}
@Override
public String toString() {
return "User.toString()";
}
}
使用Objenesis實例化對象
import org.objenesis.Objenesis;
import org.objenesis.ObjenesisStd;
import org.objenesis.instantiator.ObjectInstantiator;
public class TestObjenesis {
public static void main(String[] args) {
//創建Objenesis,內部包含一個實例化策略對象StdInstantiatorStrategy
Objenesis objenesis = new ObjenesisStd();
//獲取對象實例化器
ObjectInstantiator objectInstantiator = objenesis.getInstantiatorOf(User.class);
//實例化對象
System.out.println(objectInstantiator.newInstance());
}
}
輸出結果為
User.toString()
根據輸出結果可以得知確實繞過了構造器。
實現原理

默認使用的實例化策略對象類型為StdInstantiatorStrategy,會根據JVM供應商的不同,JVM版本的不同來選擇不同的實例化器。
如我們使用的HotSpot虛擬機,就會使用SunReflectionFactoryInstantiator實例化器,底層使用ReflectionFactory類來實例化對象,
關於ReflectionFactory的使用,可以查看 java魔法類之ReflectionFactory介紹 這篇博客。
如果上述條件都不滿足就會使用UnsafeFactoryInstantiator實例化器,內部使用Unsafe類的allocateInstance()方法實例化對象,
關於Unsafe,可以查看 java魔法類之Unsafe介紹 這篇博客。
使用場景

Spring中集成了Objenesis庫,在使用Cglib創建動態代理對象時就使用到了Objenesis。

Spring中定義的SpringObjenesis和Objenesis中的標准實現ObjenesisStd相比,在使用緩存時,使用Class對象代替Class名稱作為緩存的key。