前言
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。