Objenesis 底层

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 的实例化。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/585243.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

基于ST的STM32F407ZGT6嵌入式uCOS-III V3.08 操作系统工程实验

1.基于的开发板 2.原理图截图: 3.主控芯片框图与性能特点: High-performance foundation line, Arm Cortex-M4 core with DSP and FPU, 1 Mbyte of Flash memory, 168 MHz CPU, ART Accelerator, Ethernet, FSMC The STM32F405xx and STM32F407xx family is based on the high…

多家企业机密数据遭Lockbit3.0窃取,亚信安全发布《勒索家族和勒索事件监控报告》

本周态势快速感知 本周全球共监测到勒索事件87起&#xff0c;与上周相比勒索事件大幅下降。美国依旧为受勒索攻击最严重的国家&#xff0c;占比45%。 本周Cactus是影响最严重的勒索家族&#xff0c;Lockbit3.0和Bianlian恶意家族紧随其后&#xff0c;从整体上看Lockbit3.0依旧…

Meltdown 以及Linux KPTI技术简介

文章目录 前言一、Introduction二、 Background2.1 Out-of-order execution2.2 Address Spaces2.3 Cache Attacks 三、A Toy Example四、Building Blocks of the Attack4.1 Executing Transient Instructions4.2 Building a Covert Channel 五、Meltdown5.1 Attack Description…

深度学习之视觉特征提取器——LeNet

LeNet 引入 LeNet是是由深度学习巨头Yann LeCun在1998年提出&#xff0c;可以算作多层卷积网络在图像识别领域的首次成功应用。我们现在通常说的LeNet是指LeNet-5&#xff0c;最早的LeNet-1在1988年即开始研究&#xff0c;前后持续十年之久。但是&#xff0c;受限于当时计算机…

c++初阶——类和对象(下)

大家好&#xff0c;我是小锋&#xff0c;今天我们来学习我们类和对象的最后一个章节&#xff0c;我们本期的内容主要是类和对象的一些细节进行讲解 再谈构造函数 我们在初始化时有两种方式一种是函数体内初始化&#xff0c;一种是初始化列表 我们先来看看日期类的初始化 构造…

[机缘参悟-166] :周期论:万物的周期现象是这个世界有序性和稳定性保障;超越周期:在轮回中,把握周期节奏。

目录 前言&#xff1a;超越周期 一、周期是大自然和宇宙的规律&#xff0c;是天道 1.1 概述 1.2 万物的周期规律的现象 1.3 电磁波的周期 二、计算机世界中的周期性 三、佛家的生命轮回规律 四、人类社会发展的周期规律 五、经济活动的周期规律 5.1 概述 5.2 股市的…

Ieetcode——21.合并两个有序链表

21. 合并两个有序链表 - 力扣&#xff08;LeetCode&#xff09; 合并两个有序链表我们的思路是创建一个新链表&#xff0c;然后遍历已知的两个有序链表&#xff0c;并比较其节点的val值&#xff0c;将小的尾插到新链表中&#xff0c;然后继续遍历&#xff0c;直到将该两个链表…

C语言实验-函数与模块化程序设计

一&#xff1a; 编写函数fun&#xff0c;其功能是&#xff1a;输入一个正整数&#xff0c;将其每一位上为偶数的数取出重新构成一个新数并输出。主函数负责输入输出&#xff0c;如输入87653142&#xff0c;则输出8642。&#xff08;main函数->fun函数&#xff09; #define _…

【代码问题】【Pytorch】训练模型时Loss为NaN或INF

解决方法或者问题排查&#xff1a; 加归一化层&#xff1a; 我的问题是我新增的一个模块与原来的模块得到的张量相加&#xff0c;原张量是归一化后的&#xff0c;我的没有&#xff1a; class Module(nn.Module):def __init__(self,dim,):super().__init__()# 新增一个LayerNo…

节假日如何快速回应客户消息?

在宝贵的休闲时光或者特殊的节日期间&#xff0c;有时候由于工作、家庭等原因&#xff0c;我们很难及时回应客户的消息。那么如何在忙碌之时&#xff0c;如何确保与他人的交流畅通无阻呢&#xff1f;答案就是使用微信私域流量管理系统。 01 机器人自动回复设置 机器人自动回…

酷我音乐车机版+v6.0.1.0车机共存会员版【附带安装包下载地址】

简介 很多车机的酷我音乐app有限制&#xff0c;不能完全使用酷我音乐的所有功能。我这里分享一个可以使用全部功能的酷我音乐app&#xff0c;大家可以自行下载。 界面预览 软件下载地址【转存到自己的网盘后即可下载】 网盘地址&#xff1a;https://pan.xunlei.com/s/VNwgzNV…

Redis的事务机制能保证ACID属性吗?

目录 事务 ACID 属性 用户如何开启Redis的事务&#xff1f; 使用redis-cli客户端来展示 ​Go语言编码使用事务 Redis 的事务机制能保证哪些属性&#xff1f; 1. 原子性 语法错误 运行错误 执行EXEC时&#xff0c;Redis发生故障 Redis对事务原子性属性的保证情况 2. 一…

idm下载速度慢解决办法 idm批量下载怎么用 idm优化下载速度 Internet Download Manager解决下载速度慢的方法教程

IDM (Internet Download Manager)是一款兼容性大&#xff0c;支持多种语言的下载管理软件&#xff0c;它可以自动检测并下载网页上的内容&#xff0c;这正是这一优点&#xff0c;使得它受到了广大用户的喜爱。但是在下载的过程中&#xff0c;我们会遇到idm下载速度慢怎么回事&a…

深度学习系列66:试穿模型IDM-VTON上手

1. 模型概述 如图&#xff0c;总体流程为&#xff1a; 输入为&#xff1a;衣服的编码xg&#xff1b;人物noise的编码xt&#xff1b;人物身上衣物的mask和人体pose分割(densepose)&#xff1b;衣服部分经过两部分网络&#xff1a;1&#xff09;高级语义网络IP-Adapter&#xff…

假设检验随想

⭐️ 前言 你会吵架吗&#xff1f;你会用数学吵架吗&#xff0c;不会的话就过来看看吧&#xff0c;哈哈 西方人发明了现代意义上的概率论&#xff0c;于是就想把它推广到生产和生活中。借助一大堆的概率论中的概念&#xff0c;他们发明了假设检验&#xff0c;想利用有限的数据…

Cloudflare高级防御规则 看看我的网站如何用防御的

网站已趋于稳定&#xff0c;并且经过nginx调优。我想先分享一下Cloudflare的WAF规则&#xff0c;因为这是最有效的防御之一&#xff0c;可以抵御大量恶意攻击流量&#xff0c;我已经验证了数月。 对于海外独立站电商网站&#xff0c;Cloudflare的CDN服务是首选&#xff0c;它强…

基于SpringBoot的“在线BLOG网”的设计与实现(源码+数据库+文档+PPT)

基于SpringBoot的“在线BLOG网”的设计与实现&#xff08;源码数据库文档PPT) 开发语言&#xff1a;Java 数据库&#xff1a;MySQL 技术&#xff1a;SpringBoot 工具&#xff1a;IDEA/Ecilpse、Navicat、Maven 系统展示 在线BLOG网结构功能图 管理员登录功能界面 用户信息…

自动驾驶 | 仿真测试-HiL测试全解析

1.HiL 的定义 HiL&#xff08;Hardware-in-the-Loop&#xff09;硬件在环是计算机专业术语&#xff0c;也即是硬件在回路。通过使用 “硬件在环”(HiL) &#xff0c;可以显著降低开发时间和成本。在过去&#xff0c;开发电气机械元件或系统时,使用计算机仿真和实际的实验就已经…

大长案例 - 通用的三方接口调用方案设计

文章目录 引言身份验证防止重复提交数据完整性和加密回调地址安全事件响应可用性 设计方案概述1. API密钥生成2. 接口鉴权3. 回调地址设置4. 接口API设计 权限划分权限划分概述1. 应用ID&#xff08;AppID&#xff09;2. 应用公钥&#xff08;AppKey&#xff09;【&#xff08;…

蒸发式工业冷风机

工业冷风机是一种专为工业环境设计的降温设备&#xff0c;它通过水蒸发吸热的原理来降低环境温度。以下是关于工业冷风机降温的一些详细信息&#xff1a; 降温原理&#xff1a; 工业冷风机&#xff08;也称为蒸发式冷风机或蒸发式冷却机&#xff09;利用“水蒸发吸收热量”的物…
最新文章