項目地址:XStream, 分析的版本: v1.4.11,Demo地址:TestStream, 相關jar下載地址
本文結構
1、功能介紹
2、總體設計
3、詳細設計
4、如何提升XStream 解析速度
5、自定義Mapper和自定義Converter
6、總結
1、功能介紹
1.1簡介
提供給Java使用的XML序列化工具
1.2 如何使用
public void testPopulationOfAnObjectGraphStartingWithALiveRootObject() throws Exception {
final XStream xstream = new XStream();
//設置允許類型帶有$*字符
xstream.allowTypesByWildcard(this.getClass().getName() + "$*");
//開啓註解自動檢測
xstream.autodetectAnnotations(true);
final String xml = ""//
+ "<component>"
+ " <Host>host</Host>"
+ " <port>8000</port>"
+ "</component>";
//通過註解設置Component.class的別名爲component
xstream.alias("component", Component.class);
//把XML轉化成Component對象,(PS:如果想對象轉化成XML,則使用toXML()方法)
final Component component = xstream.fromXML(xml);
}
public static class Component {
//設置host的別名爲Host
@XStreamAlias("Host")
String host;
int port;
}
2、總體設計
2.1 XStream 總體由五部分組成
-
XStream 作爲客戶端對外提供XML解析與轉換的相關方法。
-
AbstractDriver 爲XStream提供流解析器和編寫器的創建。目前支持XML(DOM,PULL)、JSON解析器。解析器HierarchicalStreamReader,編寫器HierarchicalStreamWriter(PS:XStream默認使用了XppDriver)。
-
MarshallingStrategy 編組和解組策略的核心接口,兩個方法:
marshal:編組對象圖
unmarshal:解組對象圖
TreeUnmarshaller 樹解組程序,調用mapper和Converter把XML轉化成java對象,裏面的start方法開始解組,convertAnother方法把class轉化成java對象。
TreeMarshaller 樹編組程序,調用mapper和Converter把java對象轉化成XML,裏面的start方法開始編組,convertAnother方法把java對象轉化成XML。
它的抽象子類AbstractTreeMarshallingStrategy有抽象兩個方法
createUnmarshallingContext
createMarshallingContext
用來根據不同的場景創建不同的TreeUnmarshaller子類和TreeMarshaller子類,使用了策略模式,如ReferenceByXPathMarshallingStrategy創建ReferenceByXPathUnmarshaller,ReferenceByIdMarshallingStrategy創建ReferenceByIdUnmarshaller(PS:XStream默認使用ReferenceByXPathMarshallingStrategy)。 -
Mapper 映射器,XML的elementName通過mapper獲取對應類、成員、屬性的class對象。支持解組和編組,所以方法是成對存在real 和serialized,他的子類MapperWrapper作爲裝飾者,包裝了不同類型映射的映射器,如AnnotationMapper,ImplicitCollectionMapper,ClassAliasingMapper。
-
ConverterLookup 通過Mapper獲取的Class對象後,接着調用lookupConverterForType獲取對應Class的轉換器,將其轉化成對應實例對象。DefaultConverterLookup是該接口的實現類,同時實現了ConverterRegistry的接口,所有DefaultConverterLookup具備查找converter功能和註冊converter功能。所有註冊的轉換器按一定優先級組成由TreeSet保存的有序集合(PS:XStream 默認使用了DefaultConverterLookup)。
3、詳細設計
StartUML寫的XStreamUML原文件和圖片下載地址
4、核心功能介紹
4.1 Xstream中Mapper的原理
####1. Mapper的構建過程
//XStream 構建映射器,通過MapperWrapper裝飾者,將各個不同功能的映射器進行包裝成Mapper
//通過映射器獲取節點名的類型Class。
private Mapper buildMapper() {
Mapper mapper = new DefaultMapper(classLoaderReference);
if (useXStream11XmlFriendlyMapper()) {
mapper = new XStream11XmlFriendlyMapper(mapper);
}
mapper = new DynamicProxyMapper(mapper);
mapper = new PackageAliasingMapper(mapper);
mapper = new ClassAliasingMapper(mapper);
mapper = new ElementIgnoringMapper(mapper);
mapper = new FieldAliasingMapper(mapper);
mapper = new AttributeAliasingMapper(mapper);
mapper = new SystemAttributeAliasingMapper(mapper);
mapper = new ImplicitCollectionMapper(mapper, reflectionProvider);
mapper = new OuterClassMapper(mapper);
mapper = new ArrayMapper(mapper);
mapper = new DefaultImplementationsMapper(mapper);
mapper = new AttributeMapper(mapper, converterLookup, reflectionProvider);
mapper = new EnumMapper(mapper);
mapper = new LocalConversionMapper(mapper);
mapper = new ImmutableTypesMapper(mapper);
if (JVM.isVersion(8)) {
mapper = buildMapperDynamically("com.thoughtworks.xstream.mapper.LambdaMapper", new Class[]{Mapper.class},
new Object[]{mapper});
}
mapper = new SecurityMapper(mapper);
mapper = new AnnotationMapper(mapper, converterRegistry, converterLookup, classLoaderReference,
reflectionProvider);
mapper = wrapMapper((MapperWrapper)mapper);
mapper = new CachingMapper(mapper);
return mapper;
}
//PackageAliasingMapper繼承自MapperWrapper
public PackageAliasingMapper(final Mapper wrapped) {
//調用MapperWrapper構造器
super(wrapped);
}
//包裝過程----》把Mapper中的方法按不同功能劃分成不同實現類,並通過裝飾者進行裝載,包裝過程核心方法如下:
public MapperWrapper(final Mapper wrapped) {
this.wrapped = wrapped;
if (wrapped instanceof MapperWrapper) {
// 2.開始包裝
final MapperWrapper wrapper = (MapperWrapper)wrapped;
final Map<String, Mapper> wrapperMap = new HashMap<>();
wrapperMap.put("aliasForAttribute", wrapper.aliasForAttributeMapper);
wrapperMap.put("aliasForSystemAttribute", wrapper.aliasForSystemAttributeMapper);
wrapperMap.put("attributeForAlias", wrapper.attributeForAliasMapper);
wrapperMap.put("defaultImplementationOf", wrapper.defaultImplementationOfMapper);
wrapperMap.put("getConverterFromAttribute", wrapper.getConverterFromAttributeMapper);
wrapperMap.put("getConverterFromItemType", wrapper.getConverterFromItemTypeMapper);
wrapperMap.put("getFieldNameForItemTypeAndName", wrapper.getFieldNameForItemTypeAndNameMapper);
wrapperMap.put("getImplicitCollectionDefForFieldName", wrapper.getImplicitCollectionDefForFieldNameMapper);
wrapperMap.put("getItemTypeForItemFieldName", wrapper.getItemTypeForItemFieldNameMapper);
wrapperMap.put("getLocalConverter", wrapper.getLocalConverterMapper);
wrapperMap.put("isIgnoredElement", wrapper.isIgnoredElementMapper);
wrapperMap.put("isImmutableValueType", wrapper.isImmutableValueTypeMapper);
wrapperMap.put("isReferenceable", wrapper.isReferenceableMapper);
wrapperMap.put("realClass", wrapper.realClassMapper);
wrapperMap.put("realMember", wrapper.realMemberMapper);
wrapperMap.put("serializedClass", wrapper.serializedClassMapper);
wrapperMap.put("serializedMember", wrapper.serializedMemberMapper);
wrapperMap.put("shouldSerializeMember", wrapper.shouldSerializeMemberMapper);
final Method[] methods = wrapped.getClass().getMethods();
for (final Method method : methods) {
if (method.getDeclaringClass() != MapperWrapper.class) {
final String name = method.getName();
if (wrapperMap.containsKey(name)) {
//wrapped類中實現的方法且wrapperMap包含的,放入map中
wrapperMap.put(name, wrapped);
}
}
}
//把wrapperMap中的值重新賦值給mapper中的變量
aliasForAttributeMapper = wrapperMap.get("aliasForAttribute");
aliasForSystemAttributeMapper = wrapperMap.get("aliasForSystemAttribute");
attributeForAliasMapper = wrapperMap.get("attributeForAlias");
defaultImplementationOfMapper = wrapperMap.get("defaultImplementationOf");
getConverterFromAttributeMapper = wrapperMap.get("getConverterFromAttribute");
getConverterFromItemTypeMapper = wrapperMap.get("getConverterFromItemType");
getFieldNameForItemTypeAndNameMapper = wrapperMap.get("getFieldNameForItemTypeAndName");
getImplicitCollectionDefForFieldNameMapper = wrapperMap.get("getImplicitCollectionDefForFieldName");
getItemTypeForItemFieldNameMapper = wrapperMap.get("getItemTypeForItemFieldName");
getLocalConverterMapper = wrapperMap.get("getLocalConverter");
isIgnoredElementMapper = wrapperMap.get("isIgnoredElement");
isImmutableValueTypeMapper = wrapperMap.get("isImmutableValueType");
isReferenceableMapper = wrapperMap.get("isReferenceable");
realClassMapper = wrapperMap.get("realClass");
realMemberMapper = wrapperMap.get("realMember");
serializedClassMapper = wrapperMap.get("serializedClass");
serializedMemberMapper = wrapperMap.get("serializedMember");
shouldSerializeMemberMapper = wrapperMap.get("shouldSerializeMember");
} else {
// 1. 初始化DefaultMapper初始化各個映射器
aliasForAttributeMapper = wrapped;
aliasForSystemAttributeMapper = wrapped;
attributeForAliasMapper = wrapped;
defaultImplementationOfMapper = wrapped;
getConverterFromAttributeMapper = wrapped;
getConverterFromItemTypeMapper = wrapped;
getFieldNameForItemTypeAndNameMapper = wrapped;
getImplicitCollectionDefForFieldNameMapper = wrapped;
getItemTypeForItemFieldNameMapper = wrapped;
getLocalConverterMapper = wrapped;
isIgnoredElementMapper = wrapped;
isImmutableValueTypeMapper = wrapped;
isReferenceableMapper = wrapped;
realClassMapper = wrapped;
realMemberMapper = wrapped;
serializedClassMapper = wrapped;
serializedMemberMapper = wrapped;
shouldSerializeMemberMapper = wrapped;
}
}
2. Mapper的映射的查找過程
比如,根據elementName查找對應的Class,首先調用realClass方法,然後realClass方法會在所有包裝層中一層層往下找,並還原elementName的信息,比如在ClassAliasingMapper根據component別名得出Component類,最後在DefaultMapper中調用realClass創建出Class。
CachingMapper——>SecurityMapper——>ArrayMapper———>ClassAliasingMapper——>PackageAliasingMapper———>DynamicProxyMapper———>DefaultMapper
DefaultMapper的realClass方法
@Override
public Class<?> realClass(final String elementName) {
return Class.forName(elementName, initialize, classLoader);
}
比如對於一個elementNode爲component,下圖是調用的方法棧。
4.2、XStream中Converter的原理
1.Converter的註冊
註冊轉化器並設置優先級,Null最高,基本類型第二高,常用bean普通優先級,反射低最低優先級,序列化對象和Externalizable低優先級,。
registerConverter(new ReflectionConverter(mapper, reflectionProvider), PRIORITY_VERY_LOW);
registerConverter(new SerializableConverter(mapper, reflectionProvider, classLoaderReference), PRIORITY_LOW);
registerConverter(new ExternalizableConverter(mapper, classLoaderReference), PRIORITY_LOW);
registerConverter(new NullConverter(), PRIORITY_VERY_HIGH);
registerConverter(new IntConverter(), PRIORITY_NORMAL);
registerConverter(new FloatConverter(), PRIORITY_NORMAL);
使用二叉樹TreeSet來保存Converter並根據優先級排序所有轉換器,排好序的集合
方便後面對converter的查找。
private final PrioritizedList<Converter> converters = new PrioritizedList<>();
@Override
public void registerConverter(final Converter converter, final int priority) {
typeToConverterMap.clear();
converters.add(converter, priority);
}
public class PrioritizedList<E> implements Iterable<E> {
//實際是TreeSet來存儲Converters
private final Set<PrioritizedItem<E>> set = new TreeSet<>();
}
2. 查找Converter
public Converter lookupConverterForType(final Class<?> type) {
//先查詢緩存的類型對應的轉換器集合
final Converter cachedConverter = type != null ? typeToConverterMap.get(type.getName()) : null;
if (cachedConverter != null) {
//返回找到的緩存轉換器
return cachedConverter;
}
final Map<String, String> errors = new LinkedHashMap<>();
//遍歷轉換器集合
for (final Converter converter : converters) {
try {
//判斷是不是符合的轉換器
if (converter.canConvert(type)) {
if (type != null) {
//緩存類型對應的轉換器
typeToConverterMap.put(type.getName(), converter);
}
//返回找到的轉換器
return converter;
}
} catch (final RuntimeException | LinkageError e) {
errors.put(converter.getClass().getName(), e.getMessage());
}
}
}
4.3、XML中HierarchicalStreamDriver的原理
HierarchicalStreamDriver通過下面方法創建Writer和Reader
HierarchicalStreamWriter createWriter(Writer out);
HierarchicalStreamReader createReader(Reader in);
HierarchicalStreamDriver的實現類爲AbstractDriver,使用XML DOM解析,把整個XML加載進內存,缺點是佔內存。
private HierarchicalStreamReader createReader(final InputSource source) {
documentBuilderFactory = createDocumentBuilderFactory();
final DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
if (encoding != null) {
source.setEncoding(encoding);
}
}
AbstractDriver實現類XppDriver,創建的是XmlPullParser 解析器XML的PULL解析,他是Xpp版本1(XStream默認使用該解析器)
public static synchronized XmlPullParser createDefaultParser() throws XmlPullParserException {
if (factory == null) {
factory = XmlPullParserFactory.newInstance();
}
return factory.newPullParser();
}
AbstractDriver實現類Xpp3Driver,創建的是Xpp3的XML解析器MXParser,他是Xpp3 解析器速度要快於Xpp,也是PULL解析XML。
@Override
protected XmlPullParser createParser() {
return new MXParser();
}
AbstractDriver實現類JsonHierarchicalStreamDriver創建的是Json解析器,當目前只支持把java對象序列化成JSON,不支持把JSON反序列化成java對象。
4.4、XML是如何轉化成Java對象的
Xstream 調用fromXML
- 把String轉化成StringReader,HierarchicalStreamDriver通過StringReader創建HierarchicalStreamReader,最後調用MarshallingStrategy的unmarshal方法開始解組
fromXML(final String xml)
fromXML(new StringReader(xml));
unmarshal(hierarchicalStreamDriver.createReader(xml), root);
final T t = (T)marshallingStrategy.unmarshal(root, reader, dataHolder, converterLookup, mapper);
- marshallingStrategy創建出TreeUnmarshaller來並啓動解析
final TreeUnmarshaller context = createUnmarshallingContext(root, reader, converterLookup, mapper);
//start轉化
context.start(dataHolder);
- 開始組碼—————>TreeUnmarshaller的start方法
public Object start(final DataHolder dataHolder) {
this.dataHolder = dataHolder;
//通過mapper獲取對應節點的Class對象
final Class<?> type = HierarchicalStreams.readClassType(reader, mapper);
//Converter根據Class的類型轉化成java對象
final Object result = convertAnother(null, type);
for (final Runnable runnable : validationList) {
runnable.run();
}
return result;
}
- 通過節點名獲取Mapper中對應的Class
public static Class<?> readClassType(final HierarchicalStreamReader reader, final Mapper mapper) {
if (classAttribute == null) {
// 通過節點名獲取Mapper中對應的Class
Class<?> type = mapper.realClass(reader.getNodeName());
return type;
}
- 根據Class把它轉化成對應的java對象—————>TreeUnmarshaller的convertAnother方法
public Object convertAnother(final Object parent, Class<?> type, Converter converter) {
//根據mapper獲取type的正確類型
type = mapper.defaultImplementationOf(type);
if (converter == null) {
//根據type找到對應的converter
converter = converterLookup.lookupConverterForType(type);
} else {
if (!converter.canConvert(type)) {
final ConversionException e = new ConversionException("Explicitly selected converter cannot handle type");
e.add("item-type", type.getName());
e.add("converter-type", converter.getClass().getName());
throw e;
}
}
// 進行把type轉化成對應的object
return convert(parent, type, converter);
}
- 如何查找對應的Converter———>ConverterLookup中的lookupConverterForType方法
public Converter lookupConverterForType(final Class<?> type) {
// 先從緩存集合中查找Converter
final Converter cachedConverter = type != null ? typeToConverterMap.get(type.getName()) : null;
if (cachedConverter != null) {
return cachedConverter;
}
// 遍歷converters找到符合的Converter
for (final Converter converter : converters) {
if (converter.canConvert(type)) {
if (type != null) {
把找到的放入緩存集合中
typeToConverterMap.put(type.getName(), converter);
}
return converter;
}
}
}
- 根據找到的Converter把Type轉化成java對象————>TreeUnmarshaller的convert()
protected Object convert(final Object parent, final Class<?> type, final Converter converter) {
//調用converter unmarshal進行組碼
return converter.unmarshal(reader, this);
}
- 組碼的過程,如當Class對應的Converter爲AbstractReflectionConverter時,
根據獲取的對象,繼續讀取子節點,並轉化成對象對應的變量。
public Object unmarshal(final HierarchicalStreamReader reader, final UnmarshallingContext context) {
// 創建class的instance
Object result = instantiateNewInstance(reader, context);
//執行組碼
result = doUnmarshal(result, reader, context);
return serializationMembers.callReadResolve(result);
}
protected Object instantiateNewInstance(final HierarchicalStreamReader reader, final UnmarshallingContext context) {
//創建class的instance
return reflectionProvider.newInstance(context.getRequiredType());
}
public Object doUnmarshal(final Object result, final HierarchicalStreamReader reader,
final UnmarshallingContext context) {
//讀取裏面所有的節點
while (reader.hasMoreChildren()) {
reader.moveDown();
//獲取class中的變量
Object field = reflectionProvider.getFieldOrNull(fieldDeclaringClass, fieldName);
//判斷了class中的變量的類型
final String classAttribute = HierarchicalStreams.readClassAttribute(reader, mapper);
if (classAttribute != null) {
type = mapper.realClass(classAttribute);
} else {
type = mapper.defaultImplementationOf(field.getType());
}
//讀取class中的變量的值
value = unmarshallField(context, result, type, field);
//把變量的值賦值給Class的實例
reflectionProvider.writeField(result, fieldName, value, field.getDeclaringClass());
}
}
- 獲取Class變量的值過程同5到8,是一個循環過程,直到讀取到最後一個節點退出循環。最終獲取到java對象中的變量值也都設置,整個XML解析過程就結束了。
protected Object unmarshallField(final UnmarshallingContext context, final Object result, final Class<?> type,
final Field field) {
// Converter根據Class的類型轉化成對象
return context.convertAnother(result, type, mapper.getLocalConverter(field.getDeclaringClass(), field
.getName()));
}
4、如何提升XStream 解析速度
- 減少Converter的查找時間
我們XML都是JavaBean對象的話,那我們registerConverter時設置爲高優先級,這樣在查找對應的轉換器時就減少了查找的時間。 - 減少Mapper和Converter的查找時間
持久化Mapper查找緩存集合和Converter的查找緩存集合,在初始化時加載這兩個集合後再開始解析,。 - 使用Xpp3Driver的解析器
XStream 默認使用的是XppDriver,解析速度要慢於第三版本的Xpp3Driver。原因:第三版本的Xpp3Driver使用了Xpp3 parser,具體原理本文不做分析。
5、自定義Mapper和自定義Converter
6、總結
全文通過舉XStream的使用例子作爲文章開頭部分,接着分析了XStream的總體設計,並把XStream分爲五部分一一做了介紹。接着詳細地介紹了Mapper的原理、Converter的原理、HierarchicalStreamDriver的原理,XML是如何轉化成Java對象的,最後根據原理講了如何提高XStream 解析XML速度。