dubbo里面的JavaBeanDescriptor是怎么进行序列化和反序列化的?
序列化的操作就是:1 变成JavaBeanAccessor对象。 2 把value值塞进去 3通过IdentityHashMap(普通hashmap可以通过equals方法刷新掉,IdentityHashMap用内存地址作为key)对已经序列化好的描述符缓存起来复用
变成JavaBeanAccessor对象:
if (cl.isEnum()) {
return new JavaBeanDescriptor(cl.getName(), JavaBeanDescriptor.TYPE_ENUM);
} else if (cl.isArray()) {
return new JavaBeanDescriptor(cl.getComponentType().getName(), JavaBeanDescriptor.TYPE_ARRAY);
} else if (ReflectUtils.isPrimitive(cl)) {
return new JavaBeanDescriptor(cl.getName(), JavaBeanDescriptor.TYPE_PRIMITIVE);
} else if (Class.class.equals(cl)) {
return new JavaBeanDescriptor(Class.class.getName(), JavaBeanDescriptor.TYPE_CLASS);
} else if (Collection.class.isAssignableFrom(cl)) {
return new JavaBeanDescriptor(cl.getName(), JavaBeanDescriptor.TYPE_COLLECTION);
} else if (Map.class.isAssignableFrom(cl)) {
return new JavaBeanDescriptor(cl.getName(), JavaBeanDescriptor.TYPE_MAP);
} else {
return new JavaBeanDescriptor(cl.getName(), JavaBeanDescriptor.TYPE_BEAN);
}
value值塞进去:
private static void serializeInternal(JavaBeanDescriptor descriptor, Object obj, JavaBeanAccessor accessor, IdentityHashMap<Object, JavaBeanDescriptor> cache) {
if (obj == null || descriptor == null) {
return;
}
if (obj.getClass().isEnum()) {
descriptor.setEnumNameProperty(((Enum<?>) obj).name());
} else if (ReflectUtils.isPrimitive(obj.getClass())) {
descriptor.setPrimitiveProperty(obj);
} else if (Class.class.equals(obj.getClass())) {
descriptor.setClassNameProperty(((Class<?>) obj).getName());
} else if (obj.getClass().isArray()) {
int len = Array.getLength(obj);
for (int i = 0; i < len; i++) {
Object item = Array.get(obj, i);
if (item == null) {
descriptor.setProperty(i, null);
} else {
JavaBeanDescriptor itemDescriptor = createDescriptorIfAbsent(item, accessor, cache);
descriptor.setProperty(i, itemDescriptor);
}
}
} else if (obj instanceof Collection) {
Collection collection = (Collection) obj;
int index = 0;
for (Object item : collection) {
if (item == null) {
descriptor.setProperty(index++, null);
} else {
JavaBeanDescriptor itemDescriptor = createDescriptorIfAbsent(item, accessor, cache);
descriptor.setProperty(index++, itemDescriptor);
}
}
} else if (obj instanceof Map) {
Map map = (Map) obj;
for (Object key : map.keySet()) {
Object value = map.get(key);
Object keyDescriptor = key == null ? null : createDescriptorIfAbsent(key, accessor, cache);
Object valueDescriptor = value == null ? null : createDescriptorIfAbsent(value, accessor, cache);
descriptor.setProperty(keyDescriptor, valueDescriptor);
} // ~ end of loop map
} else {
if (JavaBeanAccessor.isAccessByMethod(accessor)) {
Map<String, Method> methods = ReflectUtils.getBeanPropertyReadMethods(obj.getClass());
for (Map.Entry<String, Method> entry : methods.entrySet()) {
try {
Object value = entry.getValue().invoke(obj);
if (value == null) {
continue;
}
JavaBeanDescriptor valueDescriptor = createDescriptorIfAbsent(value, accessor, cache);
descriptor.setProperty(entry.getKey(), valueDescriptor);
} catch (Exception e) {
throw new RuntimeException(e.getMessage(), e);
}
} // ~ end of loop method map
} // ~ end of if (JavaBeanAccessor.isAccessByMethod(accessor))
if (JavaBeanAccessor.isAccessByField(accessor)) {
Map<String, Field> fields = ReflectUtils.getBeanPropertyFields(obj.getClass());
for (Map.Entry<String, Field> entry : fields.entrySet()) {
if (!descriptor.containsProperty(entry.getKey())) {
try {
Object value = entry.getValue().get(obj);
if (value == null) {
continue;
}
JavaBeanDescriptor valueDescriptor = createDescriptorIfAbsent(value, accessor, cache);
descriptor.setProperty(entry.getKey(), valueDescriptor);
} catch (Exception e) {
throw new RuntimeException(e.getMessage(), e);
}
}
} // ~ end of loop field map
} // ~ end of if (JavaBeanAccessor.isAccessByField(accessor))
} // ~ end of else
} // ~ end of method serializeInternal
1 如果是基本类型,那么直接标记成基本类型,然后把obj的具体value塞入property-map中就够了.另外对于基本类型对应的装箱类型
Number.class.isAssignableFrom(Float.class)通过这个方法也会返回true,因为这些装箱类型也是继承自number 。
装箱类型也是按照基本类型直接序列化的,塞入具体数值的
2 如果是数组:
int[] array = {1, 2, 3, 4, 5, 6, 7, 8, 9};
JavaBeanDescriptor descriptor = JavaBeanSerializeUtil.serialize(array, JavaBeanAccessor.METHOD);
是把数组作为整体当做obj传入进去,记录数组里面item的类型,并且标记成数组类型,得到一个JavaBeanDescriptor以后,只是标记了类型,还要把每个item序列化以后塞入array这个descriptor的property-map里面,也就是descriptor.setProperty(i, itemDescriptor); i表示这个item的下标,itemDescriptor表示第i个item序列化后的JavaBeanAccessor对象
3 list和isArray是不一样的,前者属于collection范畴,不过map、list、Array处理的逻辑比较类似
4 如果是自定义class:
走到这篇博文的最后一个else分支,把class-name的str存到JavaBeanAccessor对象中。塞入数值的方式是:
为了拿到这个class所有fileds的所有value,首先获取所有fileds,并且放到map里面,这个需要考虑super-class、transient、static(这个不需要序列化)。
然后通过fileds.get(instance)的反射方式拿到这个对象这个field的数值,再对这个数值翻译成描述符,最后才能把这个描述符塞入这个property-map里面

浙公网安备 33010602011771号