我是靠谱客的博主 朴素小伙,最近开发中收集的这篇文章主要介绍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的实现,代码非常短。

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
  1. MungedConstructor最快,比new只慢了2ns,比newInstance慢了1ns。
  2. unsafe很慢,花费的时间大约是MungedConstructor的3.5倍,是new的5倍,是newinstance的4倍。

最后

以上就是朴素小伙为你收集整理的objenesis的实现与性能测试的全部内容,希望文章能够帮你解决objenesis的实现与性能测试所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

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

评论列表共有 0 条评论

立即
投稿
返回
顶部