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里面