Objenesis 底层探究

5 篇文章 0 订阅

Objenesis 简介

Objenesis 是一个 Java 库,用于在不调用构造方法的情况下创建对象。由于绕过了构造方法,所以无法调用构造方法中的初始化逻辑。相应的,Objenesis 无法创建抽象类、枚举、接口的实例对象。

起源

与其称之为起源,不如说这是 Java 中反射创建对象的一种应用,先来看看 java.lang.reflect.Constructor 中的一段代码:

    @CallerSensitive
    @ForceInline // to ensure Reflection.getCallerClass optimization
    public T newInstance(Object ... initargs)
        throws InstantiationException, IllegalAccessException,
               IllegalArgumentException, InvocationTargetException
    {
        if (!override) {
            Class<?> caller = Reflection.getCallerClass();
            checkAccess(caller, clazz, clazz, modifiers);
        }
        if ((clazz.getModifiers() & Modifier.ENUM) != 0)
            throw new IllegalArgumentException("Cannot reflectively create enum objects");
        ConstructorAccessor ca = constructorAccessor;   // read volatile
        if (ca == null) {
            ca = acquireConstructorAccessor();
        }
        @SuppressWarnings("unchecked")
        T inst = (T) ca.newInstance(initargs);
        return inst;
    }

可以看到,当我们通过获取 Constructor 对象,反射创建实例对象时,实际上是通过ConstructorAccessor 中的 newInstance 方法来创建对象。这是一个 JDK 内部接口,全名是jdk.internal.reflect.ConstructorAccessor。

此处主要关注它的一个子类:jdk.internal.reflect.SerializationConstructorAccessorImpl,一个内部抽象类。

这些类都是一些特殊的类,可以被 JVM 识别,来进入其它类进行操作,而不受语言限制。

而 Objenesis 的核心,就是通过动态生成 ConstructorAccessor,来绕过原有 ConstructorAccessor 对象,调用 newInstance 方法,实现实例化。

核心

ObjenesisBase,调用入口,通过不同策略来实例化对象:

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

标准实现,采用的策略为 StdInstantiatorStrategy:

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

      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<>(type);
            }
            return new AccessibleInstantiator<>(type);
         }
         // The UnsafeFactoryInstantiator would also work. But according to benchmarks, it is 2.5
         // times slower. So I prefer to use this one
         return new SunReflectionFactoryInstantiator<>(type);
      }
      else if(PlatformDescription.isThisJVM(DALVIK)) {
         if(PlatformDescription.isAndroidOpenJDK()) {
            // Starting at Android N which is based on OpenJDK
            return new UnsafeFactoryInstantiator<>(type);
         }
         if(ANDROID_VERSION <= 10) {
            // Android 2.3 Gingerbread and lower
            return new Android10Instantiator<>(type);
         }
         if(ANDROID_VERSION <= 17) {
            // Android 3.0 Honeycomb to 4.2 Jelly Bean
            return new Android17Instantiator<>(type);
         }
         // Android 4.3 until Android N
         return new Android18Instantiator<>(type);
      }
      else if(PlatformDescription.isThisJVM(GNU)) {
         return new GCJInstantiator<>(type);
      }
      else if(PlatformDescription.isThisJVM(PERC)) {
         return new PercInstantiator<>(type);
      }

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

   }

主要是针对不同平台,调用不同的类,此处只关注 SunReflectionFactoryInstantiator:

   public SunReflectionFactoryInstantiator(Class<T> type) {
      Constructor<Object> javaLangObjectConstructor = getJavaLangObjectConstructor();
      mungedConstructor = SunReflectionFactoryHelper.newConstructorForSerialization(
          type, javaLangObjectConstructor);
      mungedConstructor.setAccessible(true);
   }

   public T newInstance() {
      try {
         return mungedConstructor.newInstance((Object[]) null);
      }
      catch(Exception e) {
         throw new ObjenesisException(e);
      }
   }

可以看到,就是通过这个动态生成的 mungedConstructor 来创建对象。

下面来看看这个 mungedConstructor 是如何生成的?

   public static <T> Constructor<T> newConstructorForSerialization(Class<T> type,
      Constructor<?> constructor) {
      Class<?> reflectionFactoryClass = getReflectionFactoryClass();
      Object reflectionFactory = createReflectionFactory(reflectionFactoryClass);

      Method newConstructorForSerializationMethod = getNewConstructorForSerializationMethod(
         reflectionFactoryClass);

      try {
         return (Constructor<T>) newConstructorForSerializationMethod.invoke(
            reflectionFactory, type, constructor);
      }
      catch(IllegalArgumentException | IllegalAccessException | InvocationTargetException e) {
         throw new ObjenesisException(e);
      }
   }

通过上文知道,ConstructorAccessor 这些 JDK 内部类,由于安全考虑,外部无法直接使用,但是 JDK 又留了特殊的入口供开发者使用,这个入口就是:sun.reflect.ReflectionFactory。

    public Constructor<?> newConstructorForSerialization(Class<?> cl,
                                                         Constructor<?> constructorToCall)
    {
        return delegate.newConstructorForSerialization(cl,
                                                       constructorToCall);
    }

而这个 delegate 就是 jdk.internal.reflect.ReflectionFactory:

    public final Constructor<?> newConstructorForSerialization(Class<?> cl,
                                                               Constructor<?> constructorToCall)
    {
        if (constructorToCall.getDeclaringClass() == cl) {
            constructorToCall.setAccessible(true);
            return constructorToCall;
        }
        return generateConstructor(cl, constructorToCall);
    }
    private final Constructor<?> generateConstructor(Class<?> cl,
                                                     Constructor<?> constructorToCall) {


        ConstructorAccessor acc = new MethodAccessorGenerator().
            generateSerializationConstructor(cl,
                                             constructorToCall.getParameterTypes(),
                                             constructorToCall.getExceptionTypes(),
                                             constructorToCall.getModifiers(),
                                             constructorToCall.getDeclaringClass());
        Constructor<?> c = newConstructor(constructorToCall.getDeclaringClass(),
                                          constructorToCall.getParameterTypes(),
                                          constructorToCall.getExceptionTypes(),
                                          constructorToCall.getModifiers(),
                                          langReflectAccess().
                                          getConstructorSlot(constructorToCall),
                                          langReflectAccess().
                                          getConstructorSignature(constructorToCall),
                                          langReflectAccess().
                                          getConstructorAnnotations(constructorToCall),
                                          langReflectAccess().
                                          getConstructorParameterAnnotations(constructorToCall));
        setConstructorAccessor(c, acc);
        c.setAccessible(true);
        return c;
    }

可以看到,最终是通过 jdk.internal.reflect.MethodAccessorGenerator 来动态的生成了 ConstructorAccessor。顺便说一下,具体的生成是采用了 JDK 内部的 ASM 操作类(jdk.internal.reflect.ClassFileAssembler)生成类的字节码,然后加载字节码,得到 Class 对象,调用 Class#newInstance 方法,得到了这个动态生成的 ConstructorAccessor 的具体对象。

下面来看看这个动态生成的 ConstructorAccessor 具体是什么。

动态 ConstructorAccessor 实现类

通读了生成这个类的字节码操作代码,翻译出的伪代码如下:

public jdk.internal.reflect.GeneratedSerializationConstructorAccessor1 extends jdk.internal.reflect.SerializationConstructorAccessorImpl {
	public GeneratedSerializationConstructorAccessor1 () {
		this.super();
	}
	public Object newInstance(Object[] args) {
		try {
		// new targetClass
		// 校验参数	
		// 1. args 为 null,跳过校验
		// 2. args 不为 null,校验参数数组长度和参数类型数组长度是否一致
		} catch (NullPointerException | ClassCastException var) {
			throw new IllegalArgumentException(var.toString());
		}
		
		try {
			// 调用 constructorToCall 的构造方法,此处由于传入 Object,即调用 Object 的无参构造
		}
		catch (Throwable var) {
			throw new InvocationTargetException(var);
		}
		
	}
}

应用

Spring 集成了Objenesis,作为在 AOP 时采用 Cglib 代理生成 Class 类后的实例化操作。

默认采用的实例化策略就是StdInstantiatorStrategy。这样,就避开了目标类的构造方法,实现了采用 Cglib 实现 AOP 时通过 ASM 动态生成的 proxyClass 的实例化。

  • 16
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

潭影空人心

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值