Java-Jackson反序列化漏洞及挖洞思路

合集下载

使用Jackson反序列化遇到的问题及解决

使用Jackson反序列化遇到的问题及解决

使⽤Jackson反序列化遇到的问题及解决Jackson反序列化遇到的问题最近在项⽬中需要使⽤Jackson把前台转来的字符转为对象,转换过程中发⽣了错误,报错如下c om.fasterxml.jackson.databind.exc.InvalidFormatException: Can not construct instance of java.util.Date fromStringvalue '2018-09-14 15:12:08': not a valid representation (error: Failed to parse Date value '2018-09-14 15:12:08': Can not parse date "2018-09-14 15:12:08": not compatible with any of standard forms ("yyyy-MM-dd'T'HH:mm:ss.SSSZ","yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", "EEE, dd MMM yyyy HH:mm:ss zzz", "yyyy-MM-dd"))原因是需要转换成的⽬标对象有Date类型的属性,前台传来的是yyyy-MM-dd HH:mm:ss类型⽽Jackson只⽀持以下四种yyyy-MM-dd'T'HH:mm:ss.SSSZyyyy-MM-dd'T'HH:mm:ss.SSS'Z'EEE, dd MMM yyyy HH:mm:ss zzzyyyy-MM-dd在⽹上查了许多⽅法都⽐较⿇烦,我太懒……发现⽤两个注解就可以轻松解决@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")@JsonFormat(pattern="yyyy-MM-dd HH:mm:ss",timezone = "GMT+8")private Date createTime;JackSon反序列化时忽略对象中不存在的json字段如果json字段⽐较多,⽽我们对象只需要部分字段,这时反序列化时会报错,可以在new ObjectMapper后加上objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);就可以在反序列化时忽略json中多余的字段了。

Java序列化反序列化原理及漏洞解决方案

Java序列化反序列化原理及漏洞解决方案

Java序列化反序列化原理及漏洞解决⽅案Java序列化Java 提供了⼀种对象序列化的机制,该机制中,⼀个对象可以被表⽰为⼀个字节序列,该字节序列包括该对象的数据、有关对象的类型的信息和存储在对象中数据的类型。

Java反序列化反序列化就是将字节序列恢复为Java对象的过程整个过程都是 Java 虚拟机(JVM)独⽴的,也就是说,在⼀个平台上序列化的对象可以在另⼀个完全不同的平台上反序列化该对象,因此可以实现多平台之间的通信、对象持久化存储,主要有如下⼏个应⽤场景。

HTTP:多平台之间的通信,管理等RMI:是 Java 的⼀组拥护开发分布式应⽤程序的 API,实现了不同操作系统之间程序的⽅法调⽤。

值得注意的是,RMI 的传输 100% 基于反序列化,Java RMI 的默认端⼝是1099端⼝。

JMX:JMX 是⼀套标准的代理和服务,⽤户可以在任何 Java 应⽤程序中使⽤这些代理和服务实现管理,中间件软件 WebLogic 的管理页⾯就是基于 JMX 开发的,⽽ JBoss 则整个系统都基于 JMX 构架。

系列化反序列化基础序列化和反序列化本⾝并不存在问题。

但当输⼊的反序列化的数据可被⽤户控制,那么攻击者即可通过构造恶意输⼊,让反序列化产⽣⾮预期的对象,在此过程中执⾏构造的任意代码。

⼀个类的对象能够序列化的成功需要两个条件该类必须实现 java.io.Serializable 接⼝该类的所有属性必须是可序列化的。

如果有⼀个属性不是可序列化的,则该属性必须注明是短暂的。

漏洞基本原理简单的反序列化Demo⾸先定义对象类Persion,包含两个参数public class implements java.io.Serializable{public String name;public int age;public void info(){System.out.println("Name:"++";nAge:"+this.age);}}在主类中声明对象,并且将对象序列化为⼆进制⽂件,将其存储到硬盘中import java.io.*;public class Main{public static void main(String [] args){将对象序列化为⼆进制⽂件Persion p = new Persion(); = "Joner";p.age = 18;try {//打开⼀个⽂件输⼊流FileOutputStream fileOut = new FileOutputStream("D:\test\test.db");//建⽴对象输⼊流ObjectOutputStream out = new ObjectOutputStream(fileOut);//输出反序列化对象out.writeObject(p);out.close();fileOut.close();System.out.printf("保存成功");}catch(IOException i){i.printStackTrace();}}进⾏反序列化import java.io.*;public class Main{public static void main(String [] args){/*从⼆进制⽂件中提取对象*/Persion persion = null;try{FileInputStream fileInputStream = new FileInputStream("D:\test\test.db");//建⽴对象输⼊流ObjectInputStream inputStream = new ObjectInputStream(fileInputStream);persion = (Persion) inputStream.readObject();inputStream.close();fileInputStream.close();}catch (ClassNotFoundException c){System.out.println("对象未找到");c.printStackTrace();return;} catch (FileNotFoundException e) {e.printStackTrace();return;} catch (IOException e) {e.printStackTrace();return;}System.out.println("反序列化对象.......");System.out.println("Name:"+);System.out.println("Age:"+persion.age);}}查看test.db⽂件的内容可以看见如下内容其中 AC ED 00 05 是java 序列化内容的特征,其中00 05 是版本信息,base64编码后为ro0AB反序列化漏洞Demo在上⾯的Demo中可以看到,进⾏反序列化时会调⽤readObject()⽅法,如果readObject⽅法书写不当就会引发漏洞。

JAVA反序列化漏洞解决办法

JAVA反序列化漏洞解决办法

JAVA反序列化漏洞解决办法⼀、漏洞描述:近期,反序列化任意代码执⾏漏洞持续发酵,越来越多的系统被爆出存在此漏洞。

Apache Commons⼯具集⼴泛应⽤于JAVA技术平台,存在Apache Commons Components InvokerTransformer反序列化任意代码执⾏漏洞, WebLogic、IBM WebSphere、JBoss、Jenkins和OpenNMS等应⽤都⼤量调⽤了Commons⼯具集,通过远程代码执⾏可对上述应⽤发起远程攻击。

⼆、漏洞解决办法:1 使⽤ SerialKiller 替换进⾏序列化操作的 ObjectInputStream 类;2 在不影响业务的情况下,临时删除掉项⽬⾥的“org/apache/commons/collections/functors/InvokerTransformer.class” ⽂件;在服务器上找org/apache/commons/collections/functors/InvokerTransformer.class类的jar,⽬前weblogic10以后都在Oracle/Middleware/modules下mons.collections_3.2.0.jar,创建临时⽬录tt,解压之后删除InvokerTransformer.class类后再打成mons.collections_3.2.0.jar覆盖Oracle/Middleware/modules下,重启所有服务。

如下步骤是linux详细操作⽅法:A)mkdir ttB)cp -r Oracle/Middleware/modules/mons.collections_3.2.0.jar ./ttC)jar xf Oracle/Middleware/modules/mons.collections_3.2.0.jarD)cd org/apache/commons/collections/functorsE)rm -rf InvokerTransformer.classF)jar cf mons.collections_3.2.0.jar org/* META-INF/*G)mv mons.collections_3.2.0.jar Oracle/Middleware/modules/H)重启服务三、漏洞解决办法:1、假如不是处理weblogic⾃带的mons.collections_3.2.0.jar,⽽是修改应⽤代码collections_*.jar,⼀定在发版本不能覆盖。

Java反序列化漏洞研究

Java反序列化漏洞研究

Java反序列化漏洞研究Java反序列化漏洞研究1. 漏洞原理java序列化就是把对象转换成字节流,便于保存在内存、⽂件、数据库中;反序列化即逆过程,由字节流还原成对象。

当反序列化的输⼊来源于程序外部,可以被⽤户控制,恶意⽤户便可以构造恶意的字节流,经反序列化之后得到精⼼构造的恶意对象。

也就是说⼀些java应⽤的数据在⽹络中传输,我们把⾥⾯的序列化数据抠出来,替换成我们的payload,应⽤程序接收之后把payload 进⾏反序列化,构造的恶意功能(如命令执⾏)就被执⾏了。

实际过程中直接忽略PCA的存在,hacker先于PCB完成⼀些前期的交互。

那么问题来了,如何构造能执⾏任意命令的payload?需要依赖于什么条件?哪些应⽤会在⽹络中传输序列化的数据?这些数据有什么特征?1. 序列化与反序列化原理上述代码说明了反序列化的过程,Java中通过writeObject()函数对对象进⾏序列化,将有结构的数据转换成为⽆结构的⼆进制串。

通过readObject()函数将⼆进制串反序列化还原成对象。

执⾏到12⾏时⽣成了⼀个String类型的对象。

执⾏到16⾏已经将序列化数据写⼊到object.db中了,前⾯的四个字节AC ED 00 05开头,后⾯会经常⽤到。

执⾏到24⾏,完成反序列化过程,将对象还原,此时对象id不同,其他均相同。

1. 构造执⾏任意命令的payload下⾯的代码能快速的体验payload是如何构造的。

程序1的RunInvo类,构造了⼀个MAP,再⽤它构造AnnotationInvocationHandler对象,将这个对象序列化到payload.bin中。

程序2读取payload.bin中的数据,通过readObject()进⾏反序列化,代码得到执⾏,弹出计算器,如下图所⽰。

代码执⾏关键点:AnnotationInvocationHandler,TransformedMap.decorate,InvokerTransformer从序列化数据传⼊readObject()开始解释为什么要依赖于这⼏个关键点。

Java安全之Fastjson反序列化漏洞分析

Java安全之Fastjson反序列化漏洞分析

Java安全之Fastjson反序列化漏洞分析Java安全之Fastjson反序列化漏洞分析⾸发:先知论坛0x00 前⾔在前⾯的RMI和JNDI注⼊学习⾥⾯为本次的Fastjson打了⼀个⽐较好的基础。

利于后⾯的漏洞分析。

0x01 Fastjson使⽤在分析漏洞前,还需要学习⼀些Fastjson库的简单使⽤。

Fastjson概述FastJson是啊⾥巴巴的的开源库,⽤于对JSON格式的数据进⾏解析和打包。

其实简单的来说就是处理json格式的数据的。

例如将json转换成⼀个类。

或者是将⼀个类转换成⼀段json数据。

在我前⾯的学习系列⽂章中其实有⽤到jackson。

其作⽤和Fastjson差不多,都是处理json数据。

可参考该篇⽂章:。

其实在jackson⾥⾯也是存在反序列化漏洞的,这个后⾯去分析,这⾥不做赘述。

Fastjson使⽤使⽤⽅式://序列化String text = JSON.toJSONString(obj);//反序列化VO vo = JSON.parse(); //解析为JSONObject类型或者JSONArray类型VO vo = JSON.parseObject("{...}"); //JSON⽂本解析成JSONObject类型VO vo = JSON.parseObject("{...}", VO.class); //JSON⽂本解析成VO.class类Fastjson序列化代码实例:定义⼀个实体类package com.fastjson.demo;public class User {private String name;private int age;public User() {}@Overridepublic String toString() {return "User{" +"name='" + name + '\'' +", age=" + age +'}';}public String getName() {return name;}public void setName(String name) { = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}public User(String name, int age) { = name;this.age = age;}}定义⼀个test类:package com.fastjson.demo;import com.alibaba.fastjson.JSON;public class test {public static void main(String[] args) {User user = new User();user.setAge(18);user.setName("xiaoming");String s = JSON.toJSONString(user);System.out.println(s);}}运⾏后结果为:{"age":18,"name":"xiaoming"}这是⼀段标准模式下的序列化成JSON的代码,下⾯来看另⼀段。

Java反序列化漏洞学习

Java反序列化漏洞学习

Java反序列化漏洞学习序列化是Java提供的⼀种对象持久化保存的技术。

常规对象在程序结束后会被回收,如果想把对象持久保存⽅便下次使⽤,需要序列化和反序列化。

序列化有两个前提:类必须实现.serializable接⼝类所有字段都必须是可序列化的反序列化漏洞利⽤原理1. 利⽤重写ObjectInputStream的readObject重写ObjectInputStream的readObject⽅法时,可执⾏恶意代码。

定义⼀个类,并实现serializable接⼝:public class User implements Serializable {public String name;public int age;public String getUserInfo(){return "user name: "+ +" age: "+this.age;}}View Code对这个类进⾏序列化和反序列化(将序列化对象保存在user.txt中):public class SerializeDemo {public static void main(String[] args) throws IOException, ClassNotFoundException {User user = new User(); = "路⼈";user.age = 25;try {FileOutputStream fileOut = new FileOutputStream("user.txt");ObjectOutputStream out = new ObjectOutputStream(fileOut);out.writeObject(user);out.close();fileOut.close();System.out.println("Serialized done");} catch (IOException e) {e.printStackTrace();}User user_out = null;FileInputStream fileInput = new FileInputStream("user.txt");ObjectInputStream in = new ObjectInputStream(fileInput);user_out = (User) in.readObject();in.close();fileInput.close();System.out.println(user_out.getUserInfo());}}View Code执⾏结果:user类重写readObject⽅法,并将恶意代码写在重写⽅法中:private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {in.defaultReadObject();Runtime.getRuntime().exec("touch hello.txt");}View Code执⾏序列化和反序列化之后,恶意代码执⾏成功:2. 利⽤反射反射可以越过静态检查和类型约束,在运⾏期间访问和修改对象的属性和状态。

15.Java反序列化漏洞说明

15.Java反序列化漏洞说明

JBoss、Jenkins、OpenNMS 这些应用的反序列化漏洞能够得以利用
,就是依靠了 Apache Commons Collections这种公用库。

国家信息安全漏洞共享平台(CNVD)收录了Apache Commons Components InvokerTransformer反序列化任意代码执行漏洞( CNVD-2015-07556),该漏洞影响多款应用广泛的Web容器软件。远 程攻击者利用漏洞可在目标系统上执行任意代码,危害较大的可以取 得网站服务器控制权。
代码执行。

博客中提到,早在2015年的1月28 号,Gabriel Lawrence (@gebl)和Chris Frohoff (@frohoff)在AppSecCali上给出了一个报告,报告中介绍了Java反序列化漏洞可
以利用Apache Commons Collections 这个常用的Java 库来实现任意代码执行,
原理

如果Java 应用对用户输入,即不可信数据做了反序列化处理,并且没 有对用户可控的序列化代码进行校验而是直接进行反序列化使用,
那么攻击者可以通过构造恶意输入,让反序列化产生非预期的对象,
非预期的对象在产生过程中就有可能带来任意代码执行,触发一些 意想不到的漏洞。

所以这个问题的根源在于类 ObjectInputStream在反序列化时,没有 对生成的对象的类型做限制;假若反序列化可以设置 Java 类型的白
Java反序列化漏洞说明
Java反序列化漏洞说明
内容安排



背景说明 漏洞简介 原理 影响范围 修复建议 验证测试
背景说明

2015 年11月6日,FoxGlove Security 安全团队的@breenmachine 发布的一篇博

jackson 反序列化 枚举的问题

jackson 反序列化 枚举的问题

jackson 反序列化枚举的问题在Jackson中反序列化枚举类型时,可能会遇到一些问题。

下面是一些可能的问题和解决方法:1. 反序列化枚举失败:这可能是因为Jackson无法识别输入的字符串与枚举类型之间的映射关系。

可以使用注解`@JsonCreator`和`@JsonValue`来指定自定义的映射规则。

```javapublic enum MyEnum {VALUE1("value1"),VALUE2("value2");private String value;MyEnum(String value) {this.value = value;}@JsonCreatorpublic static MyEnum fromValue(String value) {for (MyEnum e : MyEnum.values()) {if (e.value.equals(value)) {return e;}}throw new IllegalArgumentException("Invalid value: " + value);}@JsonValuepublic String toValue() {return value;}}```2. 反序列化空字符串失败:如果输入的字符串是空字符串,Jackson默认情况下会抛出异常。

可以使用`@JsonSetter`注解指定为空字符串时的默认值。

```javapublic enum MyEnum {VALUE1,VALUE2;@JsonSetterpublic void setValue(String value) {if (value != null && !value.isEmpty()) {throw new IllegalArgumentException("Invalid value: " + value);}}}```3. 反序列化大小写不敏感的枚举:默认情况下,Jackson会按照枚举定义的顺序进行匹配,这意味着枚举类型的字符串必须完全匹配大小写。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

源码分析Jackson反序列化漏洞前言:本次分析从Java序列化和反序列化源码开始分析,进一步分析Jackson源码,找出造成漏洞的原因,最后以Jackson2.9.2版本,JDK1.80_171,resin4.0.52,CVE-2020-10673为例复现漏洞。

一.JA V A反序列化原理1.1 Class对象每一个类都有一个Class对象,Class对象包含每一个类的运行时信息,每一个类都有一个Class对象,每编译一个类就产生一个Class对象,Class类没有公共的构造方法,Class对象是在类加载的时候由JVM以及通过调用类加载器中的DefineClass()方法自动构造的,因此不能显式地声明一个Class对象。

在类加载阶段,类加载器首先检查这个类的Class对象是否已经被加载。

如果尚未加载,默认的类加载器就会根据类的全限定名查找.class文件。

一旦某个类的Class对象被载入内存,我们就可以它来创建这个类的所有对象以及获得这个类的运行时信息。

获得Class对象的方法:1).Class.forName(“类的全名”);//com.xx.xx.xx2).实例对象.getClass()3).类名.class1.2反射JA V A反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。

实现Java反射机制的类都位于ng.reflect包中:1).Class类:代表一个类2).Field类:代表类的成员变量(类的属性)3).Method类:代表类的方法4).Constructor类:代表类的构造方法5).Array类:提供了动态创建数组,以及访问数组的元素的静态方法简单反射调用代码Class clz=this.getClass();Object obj= clz.getMethod("方法名",Class对象序列).invoke(this,Object参数序列);1.3 反序列化Java 序列化是指把Java 对象转换为字节序列的过程便于保存在内存、文件、数据库中,ObjectOutputStream类的writeObject() 方法可以实现序列化。

Java 反序列化是指把字节序列恢复为Java 对象的过程,ObjectInputStream 类的readObject() 方法用于反序列化。

RMI:是Java 的一组拥护开发分布式应用程序的API,实现了不同操作系统之间程序的方法调用。

值得注意的是,RMI 的传输100% 基于反序列化,Java RMI 的默认端口是1099 端口。

JMX:JMX 是一套标准的代理和服务,用户可以在任何Java 应用程序中使用这些代理和服务实现管理,中间件软件WebLogic 的管理页面就是基于JMX 开发的,而JBoss 则整个系统都基于JMX 构架。

只有实现了Serializable接口的类的对象才可以被序列化,Serializable 接口是启用其序列化功能的接口,实现java.io.Serializable 接口的类才是可序列化的,没有实现此接口的类将不能使它们的任一状态被序列化或逆序列化。

readObject() 方法的作用正是从一个源输入流中读取字节序列,再把它们反序列化为一个对象,并将其返回,readObject() 是可以重写的,可以定制反序列化的一些行为。

readObject()主要做的事情,其实就是读取正常应该被序列化的字段信息后,再构造出一个map,再通过对象流,将原有通过对象流写进文件里面的map信息(容量,每个item信息等)全部读取出来,然后重新构造一个map,这样就使得我们保存在set里面的信息,在经历过对象流的序列化和反序列化后,都没有丢失。

1.4 readObject()分析1).进入readObject()源码,首先判断是否调用readObjectOverride(),其中enableOverride的值由ObjectInputStream类的构造函数决定,带参构造为false,无参构造为true。

但readObjectOverride()函数为空方法。

因此一般需要带参构造。

2).调用readObject0(),进入函数中,发现有一大部分的switch判断,该部分判断读入的流是什么类型。

其中readOrdinaryObject()值得注意,因为读入的大部分都是要反序列化的对象数据流。

1.5 readOrdinaryObject()函数中readClassDesc()分析1.进入readOrdinaryObject()函数,发现一开始,调用readClassDesc(),进而调用checkDeserialize()。

如下图:2.readClassDesc()函数中,switch判断顶端字节特征,选择执行的函数3.无参构造创建ObjectStreamClass()对象,调用initNonProxy().4.过程中调用了lookup(Class,boolean)方法5.进入lookup方法,生成一个带参构造的ObjectStreamClass对象,这个对象就是下面要提到的readOrdinaryObject()函数中的readSerialData()的第一个参数。

1.6 readOrdinaryObject()函数中readSerialData()分析1.进入readSerialData(),注意obj参数2.进入invokeReadObject(),发现obj参数(该参数上文提到)直接经过反射调用了里面的方法二.Jackson序列化与反序列化关键函数1.1 readValue(Object obj)序列化函数分析1.单步调试ObjectMapper初始化过程,发现在com.fasterxml.jackson.databind.deser.BeanDeserializerFactory类下,存在一个HashSet<>集合,这里是定义了一个黑名单DEFAULT_NO_DESER_CLASS_NAMES(默认不反序列化的类)并且将该黑名单设置为unmodifiableSet(不可修改,若修改则抛出异常)。

2.继续跟进,回到主程序,进入enableDefaultTyping(),这是一个Jackson在序列化和反序列化时配置的项目,当ObjectMapper对象调用该函数时,那么OBJECT_AND_NON_CONCRETE就会生效,导致需要json字符串包含类名来反序列化。

且接收封装的数组形式:[“...”,{“...”:“...”}]3.writeValueAsString(Object value)跟踪value参数,在_configAndWriteValue()函数中会判断该value对象是否是可关闭资源,如果是,则进入_configAndWriteCloseable(),对value强制转换,防止意外异常发生。

如果不是,则直接进入serializeValue()4.进入serializeValue(),通过反射获取value的Class对象5.跟踪cls参数流向,进入typedValueSerializer()6.到这里就已经很明显了,获取对象的hash值,通过该hash值从HashMap 内获取JsonSerializer<Object>对象,并返回,且此处加了synchronized(重量级锁,与本文无关,不做赘述),进行线程同步。

因为此时HashMap里面为空,因此回到findTypedValueSerializer()继续判断ser。

这里也就是Jackson通过维护一个HashMap用对象hash值来获取序列化对象。

该序列化对象是Json串内指定的类,该序列化对象可以遍历原类的所有方法。

7.继续跟进,进入_addFields(),implName是代表类属性名,从findImplicitPropertyName()内获取该函数接收的参数为[field com.caucho.config.types.ResourceRef#_location]这个参数是从AnnotatedMember类的getFullName()获取代码含义前文已有描述。

8.进入findImplicitPropertyName()函数,再次进入_findConstructorName(),并携带[field com.caucho.config.types.ResourceRef#_location]发现_findConstructorName()函数下有一个类型判断,该类型判断是判断进入的参数是否是AnnotatedParameter对象实例,通过观察代码,发现AnnotatedParameter继承自AnnotatedMember,而进入的参数是AnnotatedMember 类型,因此参数是其父类对象实例,根据JA V A多态规则,该参数显然不能是子类对象实例,而之所以参数可以传进来,是因为Annotated是AnnotatedMember 的父类,也就是向下转型合理,向上转型是不可以的。

该函数执行结果为null。

9.回到_addFields()(该函数主要目的是为了遍历Json串对象下的所有字段属性名以及对该属性名的一些判断)函数,继续往下跟进,发现implName通过getName()获取到字段名_location继续向下,进入hasIgnoreMarker()这里是判断字段是否被标记为可忽略,可以忽略的话就不会严格按照json串来映射对象,通俗的说就是Json串里面可以有对象所不包含的字段。

继续判断该字段是否被声明为transient(JA V A中添加该属性,则字段不会被序列化)。

10.继续跟进,断点到build()函数,经过几次遍历上文提到的HashMap,此时field字段值如下,这是由FieldBuilder()创建的,这是类内字段属性的完整表示。

private ng.String com.caucho.config.types.ResourceGroupCo nfig._lookupName11.所序列化的类中有多少字段就会遍历多少次,且所遍历到的字段都会存入一个POJOPropertyBuilder中,如下图props中保存了字段的许多属性。

且这些字段,会先从父类开始遍历,再遍历子类,以下是ResourceRef 和ResourceGroupConfig的所有字段12.属性字段收集完成之后,回到collectAll()函数,再次进行收集方法的过程13.进入_addMethods()函数,首先memberMethods会遍历所有的成员方法。

相关文档
最新文档