概述
最近看kryo的源码发现使用了一个叫做objenesis的java库,主要是用在创建对象上面,它可以不用调用构造函数就创建对象。由于并不是所有的java类都有无参构造函数,并且有的类的构造函数还是private的,所以更甚有些类是第三方的,我们不能修改源码,所以这个库还是很有用的。http://objenesis.org/details.html
objenisis包含很多平台和jvm的实现,这里我们只关心sun的jvm中的Instantiator的实现。其中的实现大约有三种:
- SunReflectionFactoryInstantiator:使用sun.reflect.ReflectionFactory来创建对象
- SunReflectionFactorySerializationInstantiator:也是使用sun.reflect.ReflectionFactory来创建对象,但是为了兼容序列化,需要找到第一个没有实现serializable接口的父类,性能有一定的损耗。
- UnsafeFactoryInstantiator:使用sun.misc.Unsafe.allocateInstance来创建对象
还有一种MagicInstantiator看上去没什么用。
SunReflectionFactoryInstantiator
我们先来看看SunReflectionFactoryInstantiator的实现,代码非常短。
public SunReflectionFactoryInstantiator(Class<T> type) {
//获得object的对象
Constructor<Object> javaLangObjectConstructor = getJavaLangObjectConstructor();
//这个函数是关键,主要是为这个class创建了一个新的constractor
mungedConstructor = SunReflectionFactoryHelper.newConstructorForSerialization(
type, javaLangObjectConstructor);
mungedConstructor.setAccessible(true);
}
//创建对象,大家都看的懂
public T newInstance() {
try {
return mungedConstructor.newInstance((Object[]) null);
}
catch(Exception e) {
throw new ObjenesisException(e);
}
}
//获得object的对象
private static Constructor<Object> getJavaLangObjectConstructor() {
try {
return Object.class.getConstructor((Class[]) null);
}
catch(NoSuchMethodException e) {
throw new ObjenesisException(e);
}
}
从上面的代码可以看到SunReflectionFactoryHelper.newConstructorForSerialization函数是关键,我们去看看这个源码:
public static <T> Constructor<T> newConstructorForSerialization(Class<T> type,
Constructor<?> constructor) {
//下面两行这里主要就是获得sun.reflect.ReflectionFactory的对象
Class<?> reflectionFactoryClass = getReflectionFactoryClass();
Object reflectionFactory = createReflectionFactory(reflectionFactoryClass);
//获得newConstructorForSerialization方法的method对象
Method newConstructorForSerializationMethod = getNewConstructorForSerializationMethod(
reflectionFactoryClass);
//利用反射调用newConstructorForSerialization方法获得新的constructor对象
try {
return (Constructor<T>) newConstructorForSerializationMethod.invoke(
reflectionFactory, type, constructor);
}
catch(IllegalArgumentException e) {
throw new ObjenesisException(e);
}
catch(IllegalAccessException e) {
throw new ObjenesisException(e);
}
catch(InvocationTargetException e) {
throw new ObjenesisException(e);
}
}
注释写的很清楚,关键就在sun.reflect.ReflectionFactory的newConstructorForSerialization方法中,实际上这个方法返回的是一个无参的constructor对象,但是绝对不会与原来的constructor冲突,被称为munged 构造函数。
SunReflectionFactorySerializationInstantiator
我们来看看实现
public class SunReflectionFactorySerializationInstantiator<T> implements ObjectInstantiator<T> {
private final Constructor<T> mungedConstructor;
public SunReflectionFactorySerializationInstantiator(Class<T> type) {
//获得父类中第一个没有实现serializable接口的类的class对象
Class<? super T> nonSerializableAncestor = SerializationInstantiatorHelper
.getNonSerializableSuperClass(type);
//获得无参构造函数
Constructor<? super T> nonSerializableAncestorConstructor;
try {
nonSerializableAncestorConstructor = nonSerializableAncestor
.getConstructor((Class[]) null);
}
catch(NoSuchMethodException e) {
throw new ObjenesisException(new NotSerializableException(type+" has no suitable superclass constructor"));
}
//获得munged构造函数对象,这个构造函数中会调用nonSerializableAncestorConstructor
mungedConstructor = SunReflectionFactoryHelper.newConstructorForSerialization(
type, nonSerializableAncestorConstructor);
mungedConstructor.setAccessible(true);
}
public T newInstance() {
try {
return mungedConstructor.newInstance((Object[]) null);
}
catch(Exception e) {
throw new ObjenesisException(e);
}
}
}
代码比较简单,唯一有疑问的地方是SerializationInstantiatorHelper.getNonSerializableSuperClass(type);我们来看看其中的实现
public static <T> Class<? super T> getNonSerializableSuperClass(Class<T> type) {
Class<? super T> result = type;
while(Serializable.class.isAssignableFrom(result)) {
result = result.getSuperclass();
if(result == null) {
throw new Error("Bad class hierarchy: No non-serializable parents");
}
}
return result;
}
看的出来其实就是循环去找第一个没有实现Serializable接口的父类的class对象。
UnsafeFactoryInstantiator
实现代码:
private static Unsafe unsafe;
private final Class<T> type;
public UnsafeFactoryInstantiator(Class<T> type) {
//初始化unsafe对象,不然不能使用。
if (unsafe == null) {
Field f;
try {
f = Unsafe.class.getDeclaredField("theUnsafe");
} catch (NoSuchFieldException e) {
throw new ObjenesisException(e);
}
f.setAccessible(true);
try {
unsafe = (Unsafe) f.get(null);
} catch (IllegalAccessException e) {
throw new ObjenesisException(e);
}
}
this.type = type;
}
//使用unsafe.allocateInstance的方法创建对象,然后进行强制转换。
public T newInstance() {
try {
return type.cast(unsafe.allocateInstance(type));
} catch (InstantiationException e) {
throw new ObjenesisException(e);
}
}
代码很简单。
性能测试
objenesis中有benchmark,我在我的windows电脑上跑了一下:
环境:
- 12GB内存
- oracle jdk 64位 1.8
- i5
- windows 8
结果
CreateObject.createObjectWithConstructor(new) avgt 20 6.122
± 1.672 ns/op
CreateObject.createObjectWithConstructor(newInstance) avgt 20 7.614
± 1.672 ns/op
CreateObject.createObjectWithMungedConstructor avgt 20 8.415
± 0.252 ns/op
CreateObject.createObjectWithMungedConstructorRaw avgt 20 10.413
± 1.187 ns/op
CreateObject.createObjectWithMungedConstructorRawAndCast avgt 20 10.644
± 0.186 ns/op
CreateObject.createObjectWithUnsafe avgt 20 29.813
± 1.885 ns/op
CreateObject.createObjectWithUnsafeRaw avgt 20 26.572
± 0.261 ns/op
CreateObject.createObjectWithUnsafeRawAndCast avgt 20 27.153
± 1.336 ns/op
CreateObject.createObjectWithUnsafeRawException avgt 20 27.390
± 1.090 ns/op
- MungedConstructor最快,比new只慢了2ns,比newInstance慢了1ns。
- unsafe很慢,花费的时间大约是MungedConstructor的3.5倍,是new的5倍,是newinstance的4倍。
最后
以上就是朴素小伙为你收集整理的objenesis的实现与性能测试的全部内容,希望文章能够帮你解决objenesis的实现与性能测试所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复