XStream序列化原理分析

XStream是一个Java的工具库,主要用于将对象序列化成XML或者将XML反序列化成对象,主要用途是传输、持久化、配置、单元测试。

1、XStream的序列化转换

XStream主要用toXML和fromXML进行转换:

1
2
XStream.toXML(obj)
XStream.fromXML(str)

一个转换的例子,将Student实例进行序列化,转换成xml,然后转换回来:

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
public class Student implements Serializable {
private String name;
private int age;
private School school;

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

private void readObject(java.io.ObjectInputStream s) throws IOException, ClassNotFoundException {
s.defaultReadObject();
System.out.println("XML反序列化");
}
}

public class School {
private String name;
private int classNum;

public School(String name, int classNum) {
this.name = name;
this.classNum = classNum;
}
}

public class Test {
public static void main(String[] args){
XStream xStream = new XStream();
Student people = new Student("xiaoming", 25, new School("北京大学",500));
String xml = xStream.toXML(people);
System.out.println(xml);
Student object = (Student) xStream.fromXML(xml);
}
}

序列化后的XML字符串如下:

1
2
3
4
5
6
7
8
9
10
11
12
<xstream.test.Student serialization="custom">
<xstream.test.Student>
<default>
<age>25</age>
<name>xiaoming</name>
<school>
<name>北京大学</name>
<classNum>500</classNum>
</school>
</default>
</xstream.test.Student>
</xstream.test.Student>

2、XStream序列化机制

重要部分 描述
AbstractDriver 为XStream提供流解析器和编写器
MarshallingStrategy 编组和解组策略的核心接口,两个方法:marshal-编组对象图、unmarshal-解组对象图
Mapper 映射器,XML的elementName通过mapper获取对应类、成员、属性的class对象。支持解组和编组,所以方法是成对存在real 和serialized,他的子类MapperWrapper作为装饰者,包装了不同类型映射的映射器,如AnnotationMapper,ImplicitCollectionMapper,ClassAliasingMapper。
ConverterLookup 通过Mapper获取的Class对象来得到相应的Class转换器,并将其转化成对应实例对象。DefaultConverterLookup是该接口的实现类,同时实现了ConverterRegistry的接口,具备查找converter功能和注册converter功能。
TreeMarshaller和TreeUnmarshaller 树编组和树解组程序,调用mapper和Converter把XML转化成java对象,里面的start方法开始解组,convertAnother方法把class转化成java对象。它的抽象子类AbstractTreeMarshallingStrategy有抽象两个方法 createUnmarshallingContext createMarshallingContext 用来根据不同的场景创建不同的TreeUnmarshaller子类和TreeMarshaller子类,使用了策略模式,如ReferenceByXPathMarshallingStrategy创建ReferenceByXPathUnmarshaller,ReferenceByIdMarshallingStrategy创建ReferenceByIdUnmarshaller

对象转xml字符串过程分析:

XStream.toXML方法如下,整个过程主要调用marshal处理,marshal主要用于编组对象图:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public String toXML(Object obj) {
//创建一个StringWriter,字符串缓冲区
Writer writer = new StringWriter();
this.toXML(obj, (Writer)writer);
return writer.toString();
}

public void toXML(Object obj, Writer out) {
// HierarchicalStreamDriver的实现类为AbstractDriver,使用XML DOM解析,把整个XML加载进内存,缺点是占内存。
// 这里调用的是AbstractXppDriver.createWriter
HierarchicalStreamWriter writer = this.hierarchicalStreamDriver.createWriter(out);

try {
this.marshal(obj, writer);
} finally {
writer.flush();
}

}

xStream.marshal()最终会调用到AbstractTreeMarshallingStrategy.marshal()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public void marshal(Object obj, HierarchicalStreamWriter writer) {
this.marshal(obj, writer, (DataHolder)null);
}

public void marshal(Object obj, HierarchicalStreamWriter writer, DataHolder dataHolder) {
this.marshallingStrategy.marshal(writer, obj, this.converterLookup, this.mapper, dataHolder);
}

// AbstractTreeMarshallingStrategy.marshal
public void marshal(HierarchicalStreamWriter writer, Object obj, ConverterLookup converterLookup, Mapper mapper, DataHolder dataHolder) {
// 通过TreeMarshaller处理
TreeMarshaller context = this.createMarshallingContext(writer, converterLookup, mapper);
context.start(obj, dataHolder);
}

TreeMarshaller.start如下

1
2
3
4
5
6
7
8
9
10
11
12
public void start(Object item, DataHolder dataHolder) {
this.dataHolder = dataHolder;
if (item == null) {
this.writer.startNode(this.mapper.serializedClass((Class)null));
this.writer.endNode();
} else {
// 每个元素以开始节点和结束节点为一组,如<xstream.test.Student>和</xstream.test.Student>
ExtendedHierarchicalStreamWriterHelper.startNode(this.writer, this.mapper.serializedClass(item.getClass()), item.getClass());
this.convertAnother(item);
this.writer.endNode();
}
}

TreeMarshaller.convertAnother调用DefaultConverterLookup.lookupConverterForType找查找转换器

1
2
3
4
5
6
7
8
9
10
11
12
public void convertAnother(Object item) {
this.convertAnother(item, (Converter)null);
}

public void convertAnother(Object item, Converter converter) {
if (converter == null) {
converter = this.converterLookup.lookupConverterForType(item.getClass());
} else if (!converter.canConvert(item.getClass())) {
...
}
this.convert(item, converter);
}

通过DefaultConverterLookup.lookupConverterForType找到类对应的转换器,然后调用TreeMarshaller.convert进行转换。(AbstractReferenceMarshaller)TreeMarshaller.convert逻辑是调用对应转换器的doMarshal方法,如实现了Serializable的对象转换器是SerializableConverter,调用的是SerializableConverter.doMarshal

1
2
3
4
5
6
7
public void convert(Object item, Converter converter) {
if (this.getMapper().isImmutableValueType(item.getClass())) {
converter.marshal(item, this.writer, this);
} else {
...
}
}

SerializableConverter.doMarshal中核心是defaultWriteObject方法,该方法主要实现序列化所有属性域信息,和上面所述一样,按照属性的类对应的转换器来调用转换器的doMarshal方法,以此逻辑将所有属性信息序列化。比如本例中School对应的转换器是ReflectionConverter。

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
public void defaultWriteObject() {
boolean writtenDefaultFields = false;
ObjectStreamClass objectStreamClass = ObjectStreamClass.lookup(currentType[0]);
if (objectStreamClass != null) {
ObjectStreamField[] fields = objectStreamClass.getFields();

// 循环序列化所有属性
for(int i = 0; i < fields.length; ++i) {
ObjectStreamField field = fields[i];
Object value = SerializableConverter.this.readField(field, currentType[0], source);
if (value != null) {
if (!writtenClassWrapper[0]) {
writer.startNode(SerializableConverter.this.mapper.serializedClass(currentType[0]));
writtenClassWrapper[0] = true;
}

if (!writtenDefaultFields) {
writer.startNode("default");
writtenDefaultFields = true;
}

if (SerializableConverter.this.mapper.shouldSerializeMember(currentType[0], field.getName())) {
Class actualType = value.getClass();
ExtendedHierarchicalStreamWriterHelper.startNode(writer, SerializableConverter.this.mapper.serializedMember(source.getClass(), field.getName()), actualType);
Class defaultType = SerializableConverter.this.mapper.defaultImplementationOf(field.getType());
if (!actualType.equals(defaultType)) {
String attributeName = SerializableConverter.this.mapper.aliasForSystemAttribute("class");
if (attributeName != null) {
writer.addAttribute(attributeName, SerializableConverter.this.mapper.serializedClass(actualType));
}
}

context.convertAnother(value);
writer.endNode();
}
}
}

if (writtenClassWrapper[0] && !writtenDefaultFields) {
writer.startNode("default");
writer.endNode();
} else if (writtenDefaultFields) {
writer.endNode();
}

}
}

除了默认的序列化方法,在SerializableConverter.doMarshal中支持重写方法writeObject的调用,所以当类实现了Serializable并且重写了writeObject,则会调用重写的writeObject。一般在重写的writeObject方法中还是会调用SerializableConverter.defaultWriteObject方法来进行属性的序列化。

1
this.serializationMembers.callWriteObject(currentType[0], source, objectOutputStream);

反序列化fromXML类似,不再分析。

3、总结

不论是xml形式还是json形式还是Java原生序列化,本质都是将对象以某种形式表现出来,各种形式的序列化最终都是序列化类信息和该对象的属性域信息

4、参考链接

https://www.jianshu.com/p/387c568faf62