蹲厕所的熊

benjaminwhx

Objenesis-实例化对象的黑科技

2018-06-10 作者: 吴海旭


  1. Objenesis
  2. InstantiatorStrategy
  3. ObjectInstantiator
    1. SunReflectionFactoryInstantiator
    2. SunReflectionFactorySerializationInstantiator
    3. UnsafeFactoryInstantiator

说起对象实例化,想必没有人不知道吧~,最简单的就是使用new关键字来进行实例化对象的操作,首先我们来定义一个对象Person(是它还是它~)

@Data
public class Person {
    private int age;
    private String name;
}

接下来,我们来把默认的构造函数设置为private,发现不能简单new出一个实例了。

private Person() {}

但是这一步估计也难不住大多数同学,反射不就是用来干这个事的吗?用Person获取到默认的构造函数,设置可访问,最后就可以实例化出Person对象了,so easy~

Constructor<Person> constructor = Person.class.getDeclaredConstructor();
constructor.setAccessible(true);
Person person = constructor.newInstance();

但是反射的前提是得存在构造函数,但是并不是所有的java类都有无参构造函数,并且有的类的构造函数还是private的,更甚有些类是第三方的,我们不能修改源码,这个时候 objenesis 框架就可以发挥它的作用了。我fork出来加了点中文注释,地址:https://github.com/benjaminwhx/objenesis

Objenesis

Objenesis是一个小型java类库用来实例化一个特定class的对象(经过测试有效代码才1538行)。我们先来看看它内部类的继承关系:

objenesis

Objenesis内部实现使用策略模式,主要用来提供对象实例化的操作。ObjenesisBase是一个基类,内部维护一个由子类提供的策略类 InstantiatorStrategy ,由图中可以看到,策略类主要是 StdInstantiatorStrategySerializingInstantiatorStrategy 两个。

public class ObjenesisBase implements Objenesis {

    protected final InstantiatorStrategy strategy;
    protected ConcurrentHashMap<String, ObjectInstantiator<?>> cache;

    public ObjenesisBase(InstantiatorStrategy strategy) {
        this(strategy, true);
    }

    public ObjenesisBase(InstantiatorStrategy strategy, boolean useCache) {
        this.strategy = strategy;
        this.cache = useCache ? new ConcurrentHashMap<String, ObjectInstantiator<?>>() : null;
    }

    public <T> T newInstance(Class<T> clazz) {
        return getInstantiatorOf(clazz).newInstance();
    }

    @SuppressWarnings("unchecked")
    public <T> ObjectInstantiator<T> getInstantiatorOf(Class<T> clazz) {
        // 基本类型抛异常
        if(clazz.isPrimitive()) {
            throw new IllegalArgumentException("Primitive types can't be instantiated in Java");
        }
        if(cache == null) {
            return strategy.newInstantiatorOf(clazz);
        }
        ObjectInstantiator<?> instantiator = cache.get(clazz.getName());
        if(instantiator == null) {
            ObjectInstantiator<?> newInstantiator = strategy.newInstantiatorOf(clazz);
            instantiator = cache.putIfAbsent(clazz.getName(), newInstantiator);
            if(instantiator == null) {
                instantiator = newInstantiator;
            }
        }
        return (ObjectInstantiator<T>) instantiator;
    }
}

它主要就是通过子类提供的策略类来调用newInstantiatorOf 方法得到实例化器,最后通过实例化器的newInstance 方法进行实例化操作。

Objenesis的主要实现有两个,一个是 ObjenesisStdObjenesisSerializer

ObjenesisStd是实例化的标准方式,内部使用 StdInstantiatorStrategy 策略类来提供实例化帮助。

public ObjenesisStd() {
    super(new StdInstantiatorStrategy());
}

ObjenesisSerializer 是实例化的另外一种方式,内部使用 SerializingInstantiatorStrategy 策略类来提供实例化帮助。

public ObjenesisSerializer() {
    super(new SerializingInstantiatorStrategy());
}

InstantiatorStrategy

策略类最终会通过不同的策略来路由不同实现类,我们来看看标准策略类 StdInstantiatorStrategy

public class StdInstantiatorStrategy extends BaseInstantiatorStrategy {

    public <T> ObjectInstantiator<T> newInstantiatorOf(Class<T> type) {

        // HOTSPOT 或者 OPENJDK
        if (PlatformDescription.isThisJVM(HOTSPOT) || PlatformDescription.isThisJVM(OPENJDK)) {
            // Java 7 GAE was under a security manager so we use a degraded system
            if (PlatformDescription.isGoogleAppEngine() && PlatformDescription.SPECIFICATION_VERSION.equals("1.7")) {
                if (Serializable.class.isAssignableFrom(type)) {
                    // 返回序列化实例化器
                    return new ObjectInputStreamInstantiator<T>(type);
                }
                // 反射调用无参构造函数来实例化
                return new AccessibleInstantiator<T>(type);
            }
            // UnsafeFactoryInstantiator也可以工作,但是根据测试比Sun的ReflectionFactory慢了2.5倍,所以我更喜欢用它
            return new SunReflectionFactoryInstantiator<T>(type);
        } else if (PlatformDescription.isThisJVM(DALVIK)) {    // 安卓
            if (PlatformDescription.isAndroidOpenJDK()) {
                // Starting at Android N which is based on OpenJDK
                return new UnsafeFactoryInstantiator<T>(type);
            }
            if (ANDROID_VERSION <= 10) {
                // Android 2.3 Gingerbread and lower
                return new Android10Instantiator<T>(type);
            }
            if (ANDROID_VERSION <= 17) {
                // Android 3.0 Honeycomb to 4.2 Jelly Bean
                return new Android17Instantiator<T>(type);
            }
            // Android 4.3 until Android N
            return new Android18Instantiator<T>(type);
        } else if (PlatformDescription.isThisJVM(JROCKIT)) {
            // JROCKIT JVM
            return new SunReflectionFactoryInstantiator<T>(type);
        } else if (PlatformDescription.isThisJVM(GNU)) {
            return new GCJInstantiator<T>(type);
        } else if (PlatformDescription.isThisJVM(PERC)) {
            return new PercInstantiator<T>(type);
        }

        // Fallback instantiator, should work with most modern JVM
        return new UnsafeFactoryInstantiator<T>(type);

    }
}

大多数人应该都是跑在 HotSpot 或者 OpenJDK 上的,所以最终会选择 SunReflectionFactoryInstantiator 类,而针对安卓会选择另外的方式,其他虚拟机也有对应的类来实现。

ObjectInstantiator

Objenisis包含很多平台和jvm的实现,看源码的包结构可以分为:

  • android:Dalvik/Android平台的虚拟机的实例化方式。
  • basic:基本的实例化方式,有前面提到过的反射,还有序列化、Proxy方式。
  • gcj:GCJ编译器的实例化方式。
  • perc:Aonix PERC虚拟机的实例化方式。
  • sun:sun包下的一些黑科技。

这里我们只关心sun的jvm中的Instantiator的黑科技实现。其中的实现大约有三种:

  • SunReflectionFactoryInstantiator:使用 sun.reflect.ReflectionFactory 来创建对象。
  • SunReflectionFactorySerializationInstantiator:也是使用 sun.reflect.ReflectionFactory 来创建对象,但是为了兼容序列化,需要找到第一个没有实现serializable接口的父类,性能有一定的损耗。
  • UnsafeFactoryInstantiator:使用 sun.misc.Unsafe.allocateInstance 来创建对象。

还有一种MagicInstantiator看上去没什么用。看作者的测试更推荐使用SunReflectionFactoryInstantiator类来实例化对象。

SunReflectionFactoryInstantiator

@Instantiator(Typology.STANDARD)
public class SunReflectionFactoryInstantiator<T> implements ObjectInstantiator<T> {

    private final Constructor<T> mungedConstructor;

    public SunReflectionFactoryInstantiator(Class<T> type) {
        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);
        }
    }
}

最关键的还是 newConstructorForSerialization 这个方法(代码太长,缩减了一点代码)

class SunReflectionFactoryHelper {

    public static <T> Constructor<T> newConstructorForSerialization(Class<T> type,
                                                                    Constructor<?> constructor) {
        Class<?> reflectionFactoryClass = getReflectionFactoryClass();
        // 实例化ReflectionFactory类
        Object reflectionFactory = createReflectionFactory(reflectionFactoryClass);

        // 获取ReflectionFactory的newConstructorForSerialization方法
        Method newConstructorForSerializationMethod = getNewConstructorForSerializationMethod(
                reflectionFactoryClass);

        // 调用newConstructorForSerialization获得一个被改写的构造函数
        return (Constructor<T>) newConstructorForSerializationMethod.invoke(
                reflectionFactory, type, constructor);
    }

    private static Class<?> getReflectionFactoryClass() {
        return Class.forName("sun.reflect.ReflectionFactory");
    }

    private static Object createReflectionFactory(Class<?> reflectionFactoryClass) {
        Method method = reflectionFactoryClass.getDeclaredMethod(
                    "getReflectionFactory");
    }

    private static Method getNewConstructorForSerializationMethod(Class<?> reflectionFactoryClass) {
        return reflectionFactoryClass.getDeclaredMethod(
                    "newConstructorForSerialization", Class.class, Constructor.class);
    }
}

注释写的很清楚,关键就在于 sun.reflect.ReflectionFactorynewConstructorForSerialization 方法,这个方法返回的是一个无参的constructor对象,但是绝对不会与原来的constructor冲突,被称为munged 构造函数。

仿照它尝试实例化之前Person类(去掉默认的构造函数)

@Data
public class Person {
    private int age;
    private String name;

    public Person(int age, String name) {
        this.age = age;
        this.name = name;
    }
}

public static void main(String[] args) throws Exception {
    ObjectInstantiator<Person> objectInstantiator = new SunReflectionFactoryInstantiator<>(Person.class);
        Person person = objectInstantiator.newInstance();
}

反射操作比较耗时,这里可以提个代码给作者优化一下~

SunReflectionFactorySerializationInstantiator

public class SunReflectionFactorySerializationInstantiator<T> implements ObjectInstantiator<T> {

    private final Constructor<T> mungedConstructor;

    public SunReflectionFactorySerializationInstantiator(Class<T> type) {
        // 返回指定类的第一个非序列化的父类(包括自己)
        Class<? super T> nonSerializableAncestor = SerializationInstantiatorHelper
                .getNonSerializableSuperClass(type);

        Constructor<? super T> nonSerializableAncestorConstructor;
        try {
            // 获得无参构造函数(该类必须有无参构造函数)
            nonSerializableAncestorConstructor = nonSerializableAncestor
                    .getDeclaredConstructor((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);
        }
    }
}

它从指定类往父类一直找,返回第一个没有实现序列化的类,但是这个类必须要有无参的构造函数,接着还是和和刚才一样,调用 sun.reflect.ReflectionFactorynewConstructorForSerialization 方法。

为了印证猜想,让Person类实现了序列化,并继承了一个类 Animal

@Data
public class Person extends Animal implements Serializable {
    private int age;
    private String name;

    public Person(int age, String name) {
        this.age = age;
        this.name = name;
    }
}

@Data
public class Animal {
    String animalName;

    public Animal() {
        System.out.println("print animal constructor");
    }
}

把实例化器换一下,输出结果果然打印了 print animal constructor

UnsafeFactoryInstantiator

public class UnsafeFactoryInstantiator<T> implements ObjectInstantiator<T> {

    private final Unsafe unsafe;
    private final Class<T> type;

    public UnsafeFactoryInstantiator(Class<T> type) {
        this.unsafe = UnsafeUtils.getUnsafe();
        this.type = type;
    }

    public T newInstance() {
        try {
            // 使用unsafe的allocateInstance实例化对象
            return type.cast(unsafe.allocateInstance(type));
        } catch (InstantiationException e) {
            throw new ObjenesisException(e);
        }
    }
}

代码很简单,使用了 Unsafe 类的 allocateInstance 方法。



坚持原创技术分享,您的支持将鼓励我继续创作!



分享

评论