0%

Java反序列化流程梳理

序言

浮云游子意,落日故人情。

梳理Java反序列化流程。

参考panda师傅。

写在前面

有了前两篇序列化协议序列化流程梳理作为学习基础,反序列化操作就好理解多了。

我们知道序列化的核心原理:

创建一个ObjectOutputStream输出流,调用

流对象的writeObject方法,将对象序列化保存。

那么其实反序列化就是对称的:

创建一个ObjectInputStream输入流,调用ois流对象的readObject方法,将内容还原为内存中的对象。

流程分析

老规矩 还是先上demo:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class Student implements Serializable {
private static final long serialVersionUID = 2L;
private String name;
private int age;

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

public static void main(String[] args) throws Exception {
//反序列化
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("10range.ser"));
Student o = (Student)ois.readObject();
ois.close();
}
}

核心还是两句话:

1
2
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("10range.ser"));
Student o = (Student)ois.readObject();

构造函数

ObjectInputStream的构造方法:

1
2
3
4
5
6
7
8
9
10
public ObjectInputStream(InputStream in) throws IOException {
verifySubclass();
bin = new BlockDataInputStream(in);
handles = new HandleTable(10);
vlist = new ValidationList();
serialFilter = ObjectInputFilter.Config.getSerialFilter();
enableOverride = false;
readStreamHeader();
bin.setBlockDataMode(true);
}

和序列化一样,同样先是verifySubclass()查看是否可以在不违反安全约束的情况下构造此实例。

四个全局变量:

1
2
3
4
5
6
7
8
/** filter stream for handling block data conversion */
private final BlockDataInputStream bin;
/** validation callback list */
private final ValidationList vlist;
/** wire handle -> obj/exception map */
private final HandleTable handles;
/** if true, invoke readObjectOverride() instead of readObject() */
private final boolean enableOverride;

在oos里面的bout,ois里面则是bin,作用是对称的。

比较特殊的是:

visit是一个用来提供CallBack操作的验证集合

几个全局变量初始化之后:

readStreamHeader();:读取序列化文件的头部,验证魔数和序列化版本是否匹配

bin.setBlockDataMode(true);:设置为块数据读取模式

readObject

当public构造函数执行完毕之后,就该执行readObject方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public final Object readObject() throws IOException, ClassNotFoundException
{
if (enableOverride) {
return readObjectOverride();
}

// if nested read, passHandle contains handle of enclosing object
int outerHandle = passHandle;
try {
Object obj = readObject0(false);
handles.markDependency(outerHandle, passHandle);
ClassNotFoundException ex = handles.lookupException(passHandle);
if (ex != null) {
throw ex;
}
if (depth == 0) {
vlist.doCallbacks();
}
return obj;
} finally {
passHandle = outerHandle;
if (closed && depth == 0) {
clear();
}
}
}

同理,也是把主要操作交给了readObject方法来完成。

readObject0

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
/**
* Underlying readObject implementation.
*/
private Object readObject0(boolean unshared) throws IOException {
boolean oldMode = bin.getBlockDataMode();
if (oldMode) {
int remain = bin.currentBlockRemaining();
if (remain > 0) {
throw new OptionalDataException(remain);
} else if (defaultDataEnd) {
/*
* Fix for 4360508: stream is currently at the end of a field
* value block written via default serialization; since there
* is no terminating TC_ENDBLOCKDATA tag, simulate
* end-of-custom-data behavior explicitly.
*/
throw new OptionalDataException(true);
}
bin.setBlockDataMode(false);
}

byte tc;
//从序列化信息中获取第一个字节
while ((tc = bin.peekByte()) == TC_RESET) {
bin.readByte();
handleReset();
}

depth++;
totalObjectRefs++;
// 如果是对象的序列化,tc=0x73,也就是TC_OBJECT,
try {
switch (tc) {
case TC_NULL:
return readNull();

case TC_REFERENCE: // handle
return readHandle(unshared);

case TC_CLASS:
return readClass(unshared);

case TC_CLASSDESC:
case TC_PROXYCLASSDESC:
return readClassDesc(unshared);

case TC_STRING:
case TC_LONGSTRING:
return checkResolve(readString(unshared));

case TC_ARRAY:
return checkResolve(readArray(unshared));

case TC_ENUM:
return checkResolve(readEnum(unshared));

case TC_OBJECT: // Object
return checkResolve(readOrdinaryObject(unshared));

case TC_EXCEPTION:
IOException ex = readFatalException();
throw new WriteAbortedException("writing aborted", ex);

case TC_BLOCKDATA:
case TC_BLOCKDATALONG:
if (oldMode) {
bin.setBlockDataMode(true);
bin.peek(); // force header read
throw new OptionalDataException(
bin.currentBlockRemaining());
} else {
throw new StreamCorruptedException(
"unexpected block data");
}

case TC_ENDBLOCKDATA:
if (oldMode) {
throw new OptionalDataException(true);
} else {
throw new StreamCorruptedException(
"unexpected end of block data");
}

default:
throw new StreamCorruptedException(
String.format("invalid type code: %02X", tc));
}
} finally {
depth--;
bin.setBlockDataMode(oldMode);
}
}

这里匹配到这里:

1
2
case TC_OBJECT:
return checkResolve(readOrdinaryObject(unshared));

readOrdinaryObject

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
/**
* Reads and returns "ordinary" (i.e., not a String, Class,
* ObjectStreamClass, array, or enum constant) object, or null if object's
* class is unresolvable (in which case a ClassNotFoundException will be
* associated with object's handle). Sets passHandle to object's assigned
* handle.
*/
private Object readOrdinaryObject(boolean unshared)
throws IOException
{
//首先再次确认TC_OBJECT,不是的话直接报错
if (bin.readByte() != TC_OBJECT) {
throw new InternalError();
}
//读取当前类的类描述符号
ObjectStreamClass desc = readClassDesc(false);
//检查是否可以反序列化
desc.checkDeserialize();

Class<?> cl = desc.forClass();
if (cl == String.class || cl == Class.class
|| cl == ObjectStreamClass.class) {
throw new InvalidClassException("invalid class descriptor");
}

Object obj;
try {
obj = desc.isInstantiable() ? desc.newInstance() : null;
} catch (Exception ex) {
throw (IOException) new InvalidClassException(
desc.forClass().getName(),
"unable to create instance").initCause(ex);
}

passHandle = handles.assign(unshared ? unsharedMarker : obj);
ClassNotFoundException resolveEx = desc.getResolveException();
if (resolveEx != null) {
handles.markException(passHandle, resolveEx);
}

if (desc.isExternalizable()) {
readExternalData((Externalizable) obj, desc);
} else {
readSerialData(obj, desc);
}

handles.finish(passHandle);

if (obj != null &&
handles.lookupException(passHandle) == null &&
desc.hasReadResolveMethod())
{
Object rep = desc.invokeReadResolve(obj);
if (unshared && rep.getClass().isArray()) {
rep = cloneArray(rep);
}
if (rep != obj) {
// Filter the replacement object
if (rep != null) {
if (rep.getClass().isArray()) {
filterCheck(rep.getClass(), Array.getLength(rep));
} else {
filterCheck(rep.getClass(), -1);
}
}
handles.setObject(passHandle, obj = rep);
}
}

return obj;
}

ObjectStreamClass desc = readClassDesc(false);这句进入readClassDesc方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
private ObjectStreamClass readClassDesc(boolean unshared)
throws IOException
{
byte tc = bin.peekByte();
ObjectStreamClass descriptor;
switch (tc) {
case TC_NULL:
descriptor = (ObjectStreamClass) readNull();
break;
case TC_REFERENCE:
descriptor = (ObjectStreamClass) readHandle(unshared);
break;
case TC_PROXYCLASSDESC:
descriptor = readProxyDesc(unshared);
break;
case TC_CLASSDESC:
descriptor = readNonProxyDesc(unshared);
break;
default:
throw new StreamCorruptedException(
String.format("invalid type code: %02X", tc));
}
return descriptor;
}

readClassDesc读取类描述符,所以进入case TC_CLASSDESC : readNonProxyDesc

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
/**
* Reads in and returns class descriptor for a class that is not a dynamic
* proxy class. Sets passHandle to class descriptor's assigned handle. If
* class descriptor cannot be resolved to a class in the local VM, a
* ClassNotFoundException is associated with the descriptor's handle.
*/
private ObjectStreamClass readNonProxyDesc(boolean unshared)
throws IOException
{
if (bin.readByte() != TC_CLASSDESC) {
throw new InternalError();
}

ObjectStreamClass desc = new ObjectStreamClass();
int descHandle = handles.assign(unshared ? unsharedMarker : desc);
passHandle = NULL_HANDLE;

ObjectStreamClass readDesc = null;
try {
readDesc = readClassDescriptor();//进入
} catch (ClassNotFoundException ex) {
throw (IOException) new InvalidClassException(
"failed to read class descriptor").initCause(ex);
}

Class<?> cl = null;
ClassNotFoundException resolveEx = null;
bin.setBlockDataMode(true);
final boolean checksRequired = isCustomSubclass();
try {
if ((cl = resolveClass(readDesc)) == null) {
resolveEx = new ClassNotFoundException("null class");
} else if (checksRequired) {
ReflectUtil.checkPackageAccess(cl);
}
} catch (ClassNotFoundException ex) {
resolveEx = ex;
}

// Call filterCheck on the class before reading anything else
filterCheck(cl, -1);

skipCustomData();

try {
totalObjectRefs++;
depth++;
desc.initNonProxy(readDesc, cl, resolveEx, readClassDesc(false));
} finally {
depth--;
}

handles.finish(descHandle);
passHandle = descHandle;

return desc;
}

接着进入到readClassDescriptor方法:

1
2
3
4
5
6
protected ObjectStreamClass readClassDescriptor() throws IOException, ClassNotFoundException
{
ObjectStreamClass desc = new ObjectStreamClass();
desc.readNonProxy(this);
return desc;
}

进入readNonProxy,读取desc对应的元数据信息:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
void readNonProxy(ObjectInputStream in)
throws IOException, ClassNotFoundException
{
// 类名
name = in.readUTF();
// serialVersionUID
suid = Long.valueOf(in.readLong());
isProxy = false;

byte flags = in.readByte();
hasWriteObjectData =
((flags & ObjectStreamConstants.SC_WRITE_METHOD) != 0);
hasBlockExternalData =
((flags & ObjectStreamConstants.SC_BLOCK_DATA) != 0);
externalizable =
((flags & ObjectStreamConstants.SC_EXTERNALIZABLE) != 0);
boolean sflag =
((flags & ObjectStreamConstants.SC_SERIALIZABLE) != 0);
if (externalizable && sflag) {
throw new InvalidClassException(
name, "serializable and externalizable flags conflict");
}
serializable = externalizable || sflag;
isEnum = ((flags & ObjectStreamConstants.SC_ENUM) != 0);
if (isEnum && suid.longValue() != 0L) {
throw new InvalidClassException(name,
"enum descriptor has non-zero serialVersionUID: " + suid);
}

int numFields = in.readShort();
if (isEnum && numFields != 0) {
throw new InvalidClassException(name,
"enum descriptor has non-zero field count: " + numFields);
}
fields = (numFields > 0) ?
new ObjectStreamField[numFields] : NO_FIELDS;
// 从字节流中读取每一个字段的信息
for (int i = 0; i < numFields; i++) {
char tcode = (char) in.readByte();
String fname = in.readUTF();
String signature = ((tcode == 'L') || (tcode == '[')) ?
in.readTypeString() : new String(new char[] { tcode });
try {
fields[i] = new ObjectStreamField(fname, signature, false);
} catch (RuntimeException e) {
throw (IOException) new InvalidClassException(name,
"invalid descriptor for field " + fname).initCause(e);
}
}
computeFieldOffsets();
}

fields其实是类中每个字段的信息,包括:字段名称,字段类型,字段代码。

序列化操作中,在writeNonProxy中写入的TypeCodefieldNamefieldType在这里被读取。

之后会回到这里:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
readNonProxyDesc{
...
ObjectStreamClass readDesc = null;
try {
readDesc = readClassDescriptor();//进入-继续
} catch (ClassNotFoundException ex) {
throw (IOException) new InvalidClassException(
"failed to read class descriptor").initCause(ex);
}

Class<?> cl = null;
ClassNotFoundException resolveEx = null;
bin.setBlockDataMode(true);//开启data-block模式
final boolean checksRequired = isCustomSubclass();
try {
if ((cl = resolveClass(readDesc)) == null) {//进入
resolveEx = new ClassNotFoundException("null class");
} else if (checksRequired) {
ReflectUtil.checkPackageAccess(cl);
}
} catch (ClassNotFoundException ex) {
resolveEx = ex;
}

// Call filterCheck on the class before reading anything else
filterCheck(cl, -1);

skipCustomData();

try {
totalObjectRefs++;
depth++;
desc.initNonProxy(readDesc, cl, resolveEx, readClassDesc(false));
} finally {
depth--;
}

handles.finish(descHandle);
passHandle = descHandle;

return desc;
}

进入resolveClass方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
protected Class<?> resolveClass(ObjectStreamClass desc)
throws IOException, ClassNotFoundException
{
String name = desc.getName();
try {
return Class.forName(name, false, latestUserDefinedLoader());
} catch (ClassNotFoundException ex) {
Class<?> cl = primClasses.get(name);
if (cl != null) {
return cl;
} else {
throw ex;
}
}
}

这里看到Class.forName()操作,会尝试加载本地类。

其实就是反序列化的根本原因,Runtime类在这里被加载,执行了exec()

序列化操作中,oos的annotateClassannotateProxyClassreplaceObject方法

反序列化操作中对应resolveClassresolveProxyClassresolveObject方法

执行结束之后该进入filterCheck(cl, -1);

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
private void filterCheck(Class<?> clazz, int arrayLength)
throws InvalidClassException {
if (serialFilter != null) {
RuntimeException ex = null;
ObjectInputFilter.Status status;
try {
status = serialFilter.checkInput(new FilterValues(clazz, arrayLength,
totalObjectRefs, depth, bin.getBytesRead()));
} catch (RuntimeException e) {
// Preventive interception of an exception to log
status = ObjectInputFilter.Status.REJECTED;
ex = e;
}
if (status == null ||
status == ObjectInputFilter.Status.REJECTED) {
// Debug logging of filter checks that fail
if (Logging.infoLogger != null) {
Logging.infoLogger.info(
"ObjectInputFilter {0}: {1}, array length: {2}, nRefs: {3}, depth: {4}, bytes: {5}, ex: {6}",
status, clazz, arrayLength, totalObjectRefs, depth, bin.getBytesRead(),
Objects.toString(ex, "n/a"));
}
InvalidClassException ice = new InvalidClassException("filter status: " + status);
ice.initCause(ex);
throw ice;
} else {
// Trace logging for those that succeed
if (Logging.traceLogger != null) {
Logging.traceLogger.finer(
"ObjectInputFilter {0}: {1}, array length: {2}, nRefs: {3}, depth: {4}, bytes: {5}, ex: {6}",
status, clazz, arrayLength, totalObjectRefs, depth, bin.getBytesRead(),
Objects.toString(ex, "n/a"));
}
}
}
}

如果serialFilter非空,那么调用序列化筛选器,这个筛选器调用了serialFilter.checkInput方法检查序列化数据,如果检测出来了异常,那么会令statusStatus.REJECTED状态,filterCheck将会根据serialFilter.checkInput的检查结果来决定是否执行反序列化,如果checkInput()方法返回Status.REJECTED,反序列化将会被阻止,并抛出InvalidClassException()错误:

如果checkInput()方法返回Status.ALLOWED,说明程序允许反序列化。

回到上一个流程,该轮到:skipCustomData();方法:

在结束了反序列化内容检测后,会调用skipCustomData方法跳过所有数据块和对象,直到遇到TC_ENDBLOCKDATA标识:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
/**
* Skips over all block data and objects until TC_ENDBLOCKDATA is
* encountered.
*/
private void skipCustomData() throws IOException {
int oldHandle = passHandle;
for (;;) {
if (bin.getBlockDataMode()) {
bin.skipBlockData();
bin.setBlockDataMode(false);
}
switch (bin.peekByte()) {
case TC_BLOCKDATA:
case TC_BLOCKDATALONG:
bin.setBlockDataMode(true);
break;

case TC_ENDBLOCKDATA:
bin.readByte();
passHandle = oldHandle;
return;

default:
readObject0(false);
break;
}
}
}

接下来回到主线:readNonProxyDesc函数

该来到:

1
2
3
4
5
6
7
8
9
10
try {
totalObjectRefs++;
depth++;
desc.initNonProxy(readDesc, cl, resolveEx, readClassDesc(false)); // 1
} finally {
depth--;
}

handles.finish(descHandle);//2
passHandle = descHandle;

这里首先调用ObjectStreamClass中的initNonProxy方法,在这个方法里会初始化表示非代理类的类描述符。

接下来会调用调用handlesfinish方法完成引用Handle的赋值操作

最后将结果赋值给passHandle成员属性(初始定义为private int passHandle = NULL_HANDLE;

到这里,readNonProxyDesc结束

将得到的desc类描述信息赋值给descriptor变量:

1
2
3
4
5
6
7
8
9
10
11
12
private ObjectStreamClass readNonProxyDesc(boolean unshared)
throws IOException{
if (bin.readByte() != TC_CLASSDESC) {
throw new InternalError();
}

ObjectStreamClass desc = new ObjectStreamClass();
int descHandle = handles.assign(unshared ? unsharedMarker : desc);
passHandle = NULL_HANDLE;
...
return desc;
}
1
2
3
4
5
6
7
8
9
10
readClassDesc{
case TC_CLASSDESC:
descriptor = readNonProxyDesc(unshared);
break;
default:
throw new StreamCorruptedException(
String.format("invalid type code: %02X", tc));
}
return descriptor;
}

后将descriptor作为结果返回给readOrdinaryObject方法,赋值给desc;

1
2
3
4
5
6
7
8
9
10
11
private Object readOrdinaryObject(boolean unshared)
throws IOException{
if (bin.readByte() != TC_OBJECT) {
throw new InternalError();
}

ObjectStreamClass desc = readClassDesc(false);
desc.checkDeserialize();

Class<?> cl = desc.forClass();
...

到目前为止,我们拿到了类描述符号desc,继续走readOrdinaryObject方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
private Object readOrdinaryObject(boolean unshared)
throws IOException
{
if (bin.readByte() != TC_OBJECT) {
throw new InternalError();
}
// 拿到类描述符
ObjectStreamClass desc = readClassDesc(false);
//检查是否可以反序列化
desc.checkDeserialize();

Class<?> cl = desc.forClass();
if (cl == String.class || cl == Class.class
|| cl == ObjectStreamClass.class) {
throw new InvalidClassException("invalid class descriptor");
}

Object obj;
try {
obj = desc.isInstantiable() ? desc.newInstance() : null;
} catch (Exception ex) {
throw (IOException) new InvalidClassException(
desc.forClass().getName(),
"unable to create instance").initCause(ex);
}

passHandle = handles.assign(unshared ? unsharedMarker : obj);
//判断有无异常信息
ClassNotFoundException resolveEx = desc.getResolveException();
if (resolveEx != null) {
handles.markException(passHandle, resolveEx);
}

if (desc.isExternalizable()) {
readExternalData((Externalizable) obj, desc);
} else {
//读取序列化数据,给字段赋值
readSerialData(obj, desc);
}
// 处理handles的赋值
handles.finish(passHandle);

if (obj != null &&
handles.lookupException(passHandle) == null &&
desc.hasReadResolveMethod())
{
Object rep = desc.invokeReadResolve(obj);
if (unshared && rep.getClass().isArray()) {
rep = cloneArray(rep);
}
if (rep != obj) {
// Filter the replacement object
if (rep != null) {
if (rep.getClass().isArray()) {
filterCheck(rep.getClass(), Array.getLength(rep));
} else {
filterCheck(rep.getClass(), -1);
}
}
handles.setObject(passHandle, obj = rep);
}
}

return obj;
}

readSerialData

这里才是真正的开始序列化对象的函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
private void readSerialData(Object obj, ObjectStreamClass desc)
throws IOException
{
//从父类开始
ObjectStreamClass.ClassDataSlot[] slots = desc.getClassDataLayout();
for (int i = 0; i < slots.length; i++) {
ObjectStreamClass slotDesc = slots[i].desc;

if (slots[i].hasData) {
if (obj == null || handles.lookupException(passHandle) != null) {
defaultReadFields(null, slotDesc); // skip field values
} else if (slotDesc.hasReadObjectMethod()) {
ThreadDeath t = null;
boolean reset = false;
SerialCallbackContext oldContext = curContext;
if (oldContext != null)
oldContext.check();
try {
curContext = new SerialCallbackContext(obj, slotDesc);

bin.setBlockDataMode(true);
// 如果有readObject方法,执行
slotDesc.invokeReadObject(obj, this);
} catch (ClassNotFoundException ex) {
/*
* In most cases, the handle table has already
* propagated a CNFException to passHandle at this
* point; this mark call is included to address cases
* where the custom readObject method has cons'ed and
* thrown a new CNFException of its own.
*/
handles.markException(passHandle, ex);
} finally {
do {
try {
curContext.setUsed();
if (oldContext!= null)
oldContext.check();
curContext = oldContext;
reset = true;
} catch (ThreadDeath x) {
t = x; // defer until reset is true
}
} while (!reset);
if (t != null)
throw t;
}

/*
* defaultDataEnd may have been set indirectly by custom
* readObject() method when calling defaultReadObject() or
* readFields(); clear it to restore normal read behavior.
*/
defaultDataEnd = false;
} else {
// 如果没有的话就执行默认的反序列化,给字段赋值
defaultReadFields(obj, slotDesc);
}

if (slotDesc.hasWriteObjectData()) {
skipCustomData();
} else {
bin.setBlockDataMode(false);
}
} else {
if (obj != null &&
slotDesc.hasReadObjectNoDataMethod() &&
handles.lookupException(passHandle) == null)
{
slotDesc.invokeReadObjectNoData(obj);
}
}
}
}

执行结束之后就会返回一个对象obj,这个类就是序列化好的对象

回到readObject方法:

image-20210717150734443

在反序列执行完成过后,它会调用vlist成员的doCallbacks来执行完成过后的回调逻辑,然后结束所有的序列化流程。

例子

还是Student那个例子我们插入一个readObject

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class Student implements Serializable {
private static final long serialVersionUID = 2L;
private String name;
private int age;

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

private void readObject(ObjectInputStream in){
System.out.println("You are hacked!");
}

public static void main(String[] args) throws Exception {
//反序列化
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("10range.ser"));
Student o = (Student)ois.readObject();
ois.close();
}
}
image-20210717152451921

也就是说,我们需要反序列化出来的对象是Student,正好我们本地有,又因为有readObject方法,于是就直接从当前流中取出对象,执行了这个方法。

总结

步骤

  • 首先拿到desc
  • 如果有readObject方法,用反射执行
  • 没有的话给对象字段赋值
  • 序列化对象成功