XStream 源碼解析

項目地址: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,下圖是調用的方法棧。
image.png

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

  1. 把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);
  1. marshallingStrategy創建出TreeUnmarshaller來並啓動解析
final TreeUnmarshaller context = createUnmarshallingContext(root, reader, converterLookup, mapper);
//start轉化
context.start(dataHolder);
  1. 開始組碼—————>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;
    }
  1. 通過節點名獲取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;
    }
  1. 根據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);
    }
  1. 如何查找對應的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;
                }
        }
    }
  1. 根據找到的Converter把Type轉化成java對象————>TreeUnmarshaller的convert()
protected Object convert(final Object parent, final Class<?> type, final Converter converter) {
            //調用converter unmarshal進行組碼
            return converter.unmarshal(reader, this);
}


  1. 組碼的過程,如當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());
  }
}
  1. 獲取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 解析速度

  1. 減少Converter的查找時間
    我們XML都是JavaBean對象的話,那我們registerConverter時設置爲高優先級,這樣在查找對應的轉換器時就減少了查找的時間。
  2. 減少Mapper和Converter的查找時間
    持久化Mapper查找緩存集合和Converter的查找緩存集合,在初始化時加載這兩個集合後再開始解析,。
  3. 使用Xpp3Driver的解析器
    XStream 默認使用的是XppDriver,解析速度要慢於第三版本的Xpp3Driver。原因:第三版本的Xpp3Driver使用了Xpp3 parser,具體原理本文不做分析。

5、自定義Mapper和自定義Converter

demo連接

6、總結

全文通過舉XStream的使用例子作爲文章開頭部分,接着分析了XStream的總體設計,並把XStream分爲五部分一一做了介紹。接着詳細地介紹了Mapper的原理、Converter的原理、HierarchicalStreamDriver的原理,XML是如何轉化成Java對象的,最後根據原理講了如何提高XStream 解析XML速度。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章