当前位置: 首页 > 工具软件 > ActiveJ > 使用案例 >

ActiveJ学习心得——serializer(8)

薛弘阔
2023-12-01

2021SC@SDUSC

一、代码分析内容

本次介绍的是core-serializer包中的一个类——SerializerBuilder类,这是一个比较重要的类,前面没有分析,放到最后来详细分析一下。这个类的功能是扫描类的字段以进行序列化。本次博客就根据SerializerBuilder类的属性和方法来看一下它的功能是怎么实现的。

二、代码解读

1.属性
我们先来看一下这个类中定义的各种属性。

	private final DefiningClassLoader classLoader;

	private final TypeScannerRegistry<SerializerDef> registry = TypeScannerRegistry.create();

	private Class<?> implementationClass = Object.class;

	private String profile;
	private int encodeVersionMax = Integer.MAX_VALUE;
	private int decodeVersionMin = 0;
	private int decodeVersionMax = Integer.MAX_VALUE;
	private CompatibilityLevel compatibilityLevel = CompatibilityLevel.LEVEL_4;
	private int autoOrderingStart = 1;
	private int autoOrderingStride = 1;
	private boolean annotationsCompatibilityMode;

	private final Map<Object, List<Class<?>>> extraSubclassesMap = new HashMap<>();

	private final Map<Class<? extends Annotation>, Map<Class<? extends Annotation>, Function<? extends Annotation, ? extends Annotation>>> annotationAliases = new HashMap<>();

第一个属性是DefiningClassLoader 类的对象,这个类是ActiveJ中codegen模块中的类,它的作用是用于定义动态生成的类的类加载器。还支持内存缓存以及定义类的持久缓存。这里就是定义了一个类加载器。
第二个属性定义了一个SerializerDef类型扫描器注册表。
其他几个int类型的属性暂且不看,用到的时候再分析。
它定义的compatibilityLevel这个属性值得一看,CompatibilityLevel类的功能是为序列化器提供基础的版本,而这里为LEVEL_4,意思是包括以前的优化,并为boolean提供可为空的优化。
2.构造方法
这里的构造方法比较简单,就是对上面定义的classLoader进行了初始化,为这个类加载器进行赋值。

private SerializerBuilder(DefiningClassLoader classLoader) {
	this.classLoader = classLoader;
}

3.create方法
create方法的作用是使用新创建的DefiningClassLoader来创建SerializerBuilder的新实例。
它的方法类型及参数如下:

public static SerializerBuilder create(DefiningClassLoader definingClassLoader)

这个方法一开始就创建了一个SerializerBuilder 对象:SerializerBuilder builder = new SerializerBuilder(definingClassLoader);,接下来就是对这个新定义的builder进行操作。下面的方法使用了with方法,with方法的作用是添加映射以解析给定类型的SerializerDef。它使用with方法就是为了将各种数据类型给转换成序列化定义的。代码如下所示:

builder
		.with(boolean.class, ctx -> new SerializerDefBoolean(false))
		.with(char.class, ctx -> new SerializerDefChar(false))
		.with(byte.class, ctx -> new SerializerDefByte(false))
		.with(short.class, ctx -> new SerializerDefShort(false))
		.with(int.class, ctx -> new SerializerDefInt(false))
		.with(long.class, ctx -> new SerializerDefLong(false))
		.with(float.class, ctx -> new SerializerDefFloat(false))
		.with(double.class, ctx -> new SerializerDefDouble(false))

		.with(Boolean.class, ctx -> new SerializerDefBoolean(true))
		.with(Character.class, ctx -> new SerializerDefChar(true))
		.with(Byte.class, ctx -> new SerializerDefByte(true))
		.with(Short.class, ctx -> new SerializerDefShort(true))
		.with(Integer.class, ctx -> new SerializerDefInt(true))
		.with(Long.class, ctx -> new SerializerDefLong(true))
		.with(Float.class, ctx -> new SerializerDefFloat(true))
		.with(Double.class, ctx -> new SerializerDefDouble(true));

接下来又对各类型的数组进行了序列化映射,它使用了for循环,然后把定义的各类型数组一一遍历。代码如下:

for (Type type : new Type[]{
	boolean[].class, char[].class, byte[].class, short[].class, int[].class, long[].class, float[].class, double[].class,
				Object[].class}) {
	builder.with(type, ctx -> new SerializerDefArray(ctx.scanTypeArgument(0), ctx.getRawType()));
}

下面是对ip地址的序列化映射,根据我之前的博客分析,我们知道在ActiveJ中,对IPv4和IPv6地址都进行了序列化定义,它们java中是用Inet4Address和Inet6Address来表示的。它这里定义了一个LinkedHashMap,例如将Inet4Address.class与new SerializerDefInet4Address()进行映射

LinkedHashMap<Class<?>, SerializerDef> addressMap = new LinkedHashMap<>();
addressMap.put(Inet4Address.class, new SerializerDefInet4Address());
addressMap.put(Inet6Address.class, new SerializerDefInet6Address());
builder
		.with(Inet4Address.class, ctx -> new SerializerDefInet4Address())
		.with(Inet6Address.class, ctx -> new SerializerDefInet6Address())
		.with(InetAddress.class, ctx -> new SerializerDefSubclass(InetAddress.class, addressMap, 0));

再下面就是对各种容器进行做序列化定义映射。我这里所说的容器是指Collection、List、Queue、Map、HashMap、LinkedHashMap、Set、HashSet、LinkedHashSet这样的数据结构。关于后面映射的这些例如new SerializerDefCollection()都是在我们之前的分析过的impl包中的类。

builder
		.with(Collection.class, ctx -> new SerializerDefCollection(ctx.scanTypeArgument(0), Collection.class, ArrayList.class))
		.with(List.class, ctx -> new SerializerDefList(ctx.scanTypeArgument(0)))
		.with(Queue.class, ctx -> new SerializerDefCollection(ctx.scanTypeArgument(0), Queue.class, ArrayDeque.class))
		.with(Map.class, ctx -> new SerializerDefMap(ctx.scanTypeArgument(0), ctx.scanTypeArgument(1)))
		.with(HashMap.class, ctx -> new SerializerDefMap(ctx.scanTypeArgument(0), ctx.scanTypeArgument(1), HashMap.class, HashMap.class))
		.with(LinkedHashMap.class, ctx -> new SerializerDefMap(ctx.scanTypeArgument(0), ctx.scanTypeArgument(1), LinkedHashMap.class, LinkedHashMap.class))
		.with(Set.class, ctx -> new SerializerDefSet(ctx.scanTypeArgument(0)))
		.with(HashSet.class, ctx -> new SerializerDefCollection(ctx.scanTypeArgument(0), HashSet.class, HashSet.class))
		.with(LinkedHashSet.class, ctx -> new SerializerDefCollection(ctx.scanTypeArgument(0), LinkedHashSet.class, LinkedHashSet.class))

		.with(Object.class, builder::scan);

4.getAnnotation方法
getAnnotation方法定义的方式是:private <A extends Annotation> @Nullable A getAnnotation(Class<A> type, Annotation[] annotations)。这个方法是为了获取Annotation注释的方法,此方法传入的两个参数一个是A类型的类和一个Annotation数组。
此方法最开始是一个for循环,就是遍历annotations数组,然后此数组下的元素的annotationType类型是否和方法传入的参数type一致,如果一致,那么返回这个元素annotation。

	for (int i = 0; i < annotations.length; i++) {
		Annotation annotation = annotations[i];
		if (annotation.annotationType() == type) {
			return (A) annotation;
		}
	}

然后定义一个Map映射,然后也遍历aliasesMap,也是将相应位置的元素拿出来与type进行比较,然后return mapping.apply(annotation)。

	Map<Class<? extends Annotation>, Function<? extends Annotation, ? extends Annotation>> aliasesMap = annotationAliases.get(type);
	if (aliasesMap != null) {
		for (int i = 0; i < annotations.length; i++) {
			Annotation annotation = annotations[i];
			Function<Annotation, ? extends Annotation> mapping = (Function<Annotation, ? extends Annotation>) aliasesMap.get(annotation.annotationType());
			if (mapping != null) {
				return (A) mapping.apply(annotation);
			}
		}
	}

后面SerializerBuilder还有一些以with为开头的方法,下面我介绍几个。
5.withImplementationClass方法
此方法是为序列化程序添加实现类。参数是implementationClass。此类的最上面定义了private Class<?> implementationClass = Object.class;,在这个方法上重新进行赋值。

	public SerializerBuilder withImplementationClass(Class<?> implementationClass) {
		this.implementationClass = implementationClass;
		return this;
	}

6.withCompatibilityLevel方法
此方法为序列化器设置给定的CompatibilityLevel。应使用此方法确保与以前版本的序列化程序向后兼容。

	public SerializerBuilder withCompatibilityLevel(CompatibilityLevel compatibilityLevel) {
		this.compatibilityLevel = compatibilityLevel;
		return this;
	}

7.withAnnotationCompatibilityMode方法
此方法可以启用或禁用注释兼容模式。在以前的ActiveJ版本中,序列化程序注释必须直接放置在fields/getters上。为了指定具体的带注释类型,使用了path属性。现在可以直接注释类型了。但是,为了与使用path属性注释的类兼容,或者在使用可能无法解析类型使用注释的旧版本Java时,可以启用此兼容模式。

	public SerializerBuilder withAnnotationCompatibilityMode(boolean annotationsCompatibilityMode) {
		this.annotationsCompatibilityMode = annotationsCompatibilityMode;
		return this;
	}

8.withEncodeVersion
此方法用于确保序列化对象的不同版本之间的兼容性。

	public SerializerBuilder withEncodeVersion(int encodeVersionMax) {
		this.encodeVersionMax = encodeVersionMax;
		return this;
	}

后面还有许多这样的方法,它们的实现方式都大同小异,在这里就不一一赘述了。
9.build方法
从此SerializerBuilder生成二进制序列化程序。生成的序列化程序的类名将等于传递给此方法的类名。如果类加载器已经定义了序列化器类,则该类将从类加载器的缓存中获取。此外,如果链接定义类加载器具有持久字节码存储,则序列化器类将从该持久缓存中获取。

	public <T> BinarySerializer<T> build(String className, AnnotatedType type) {
		return classLoader.ensureClassAndCreateInstance(
				className,
				() -> {
					SerializerDef serializer = registry.scanner(new HashMap<>()).scan(type);
					return toClassBuilder(serializer);
				});
	}

三、总结

本次博客介绍的是core-serializer包中的SerializerBuilder类,此类是一个序列化程序创建器,分析了它的属性和最主要的create方法,还有其他一些重要的方法。

 类似资料: