我是靠谱客的博主 朴素小伙,这篇文章主要介绍objenesis的实现与性能测试,现在分享给大家,希望可以做个参考。

最近看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的实现,代码非常短。

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
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函数是关键,我们去看看这个源码:

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
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

我们来看看实现

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
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);我们来看看其中的实现

复制代码
1
2
3
4
5
6
7
8
9
10
11
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

实现代码:

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
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

结果

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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
  1. MungedConstructor最快,比new只慢了2ns,比newInstance慢了1ns。
  2. unsafe很慢,花费的时间大约是MungedConstructor的3.5倍,是new的5倍,是newinstance的4倍。

最后

以上就是朴素小伙最近收集整理的关于objenesis的实现与性能测试的全部内容,更多相关objenesis内容请搜索靠谱客的其他文章。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(48)

评论列表共有 0 条评论

立即
投稿
返回
顶部