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方法,还有其他一些重要的方法。