fastJson是很常用的序列化工具,用了这么久一直想底层看一下它的设计,探究一下它序列化和反序列化效率高的秘密。现在从最基础的用法开始,一点点揭开fastJson神秘的面纱。(版本:1.2.50)

  实际工程里,最常用的就是序列化和反序列化:

  ResultDO resultDO = new ResultDO();

  String jsonStr = JSON.toJSONString(resultDO);

  ResultDO resultDO2 = JSON.parseObject(jsonStr, new TypeReference() {});

  一.序列化

  1.先从JSON.toJSONString开始看。跟进到底层,最后会调用一个基本方法:

  public static String toJSONString(Object object, // 被序列化的对象

  SerializeConfig config, // 序列化全局配置

  SerializeFilter[] filters, //序列化的过滤器

  String dateFormat, //日期格式

  int defaultFeatures, // 默认序列化特性

  SerializerFeature... features //自定义的序列化特性) {

  SerializeWriter out = new SerializeWriter(null, defaultFeatures, features);

  try {

  JSONSerializer serializer = new JSONSerializer(out, config);

  if (dateFormat != null && dateFormat.length() != 0) {

  serializer.setDateFormat(dateFormat);

  serializer.config(SerializerFeature.WriteDateUseDateFormat, true);

  }

  if (filters != null) {

  for (SerializeFilter filter : filters) {

  serializer.addFilter(filter);

  }

  }

  serializer.write(object);

  return out.toString();

  } finally {

  out.close();

  }

  }

  (1)一开始,会初始化一个SerializeWriter,然后用自定义的features覆盖defaultFeatures配置。

  (2)然后初始化一个JSONSerializer对象,序列化结果写入SerializeWriter的buffer属性中。序列化执行的时候,会根据config查找具体的序列化处理器去做处理。

  (3)然后是对日期格式和过滤器的判断。

  SerializerFeature的用法在另一片文章里面有介绍:https://mp.csdn.net/postedit/84296853

  SerializeFilter用法不再赘述,可以戳github:https://github.com/alibaba/fastjson/wiki/SerializeFilter

  2.进入到write方法:

  public final void write(Object object) {

  if (object == null) {

  out.writeNull();

  return;

  }

  Class clazz = object.getClass();

  ObjectSerializer writer = getObjectWriter(clazz);

  try {

  writer.write(this, object, null, null, 0);

  } catch (IOException e) {

  throw new JSONException(e.getMessage(), e);

  }

  }

  在这步有一个getObjectWriter的方法,根据序列化对象的class类型,得到对应的序列化器。这段代码比较长,但可以总结为几种类型:

  (1)从指定的目录下META-INF/services/,用当前线程的类加载器去取实现AutowiredObjectSerializer的序列化器

  (2)与第一种区别的地方在于加载器不同,此时尝试用加载JSON的classLoader

  (3)当前这种是针对传进来的clazz的类型,去寻找对应的序列化器。

  这里都是常用的一些类型,比如Map,List,Collection,Date,enum,Iterator等等。还有JSON相关的一些,JSONAware,JSONSerializable,JSONStreamAware 。

  特殊处理,(a)java自带图形包java.awt (b)jdk8中的日期包、Optional、concurrent(c)oracle相关的类(d)springfox相关的类(e)guava框架中类

  (4) 代理类,包括cglib或者javassist动态代理,或是jdk自带的动态代理。

  (5)自主创建序列化器,createJavaBeanSerializer,这个之后要重点描述

  private ObjectSerializer getObjectWriter(Class clazz, boolean create) {

  //private final IdentityHashMap serializers; serializer是一个定义的缓存map,key是Type,这里存放Class类型。value是对象的序列化器

  ObjectSerializer writer = serializers.get(clazz);

  //下面是依次对不同的情况去取序列化器

  //1.从指定的目录下META-INF/services/,去取实现AutowiredObjectSerializer的序列化器

  if (writer == null) {

  try {

  final ClassLoader classLoader = Thread.currentThread().getContextClassLoader();

  for (Object o : ServiceLoader.load(AutowiredObjectSerializer.class, classLoader)) {

  if (!(o instanceof AutowiredObjectSerializer)) {

  continue;

  }

  AutowiredObjectSerializer autowired = (AutowiredObjectSerializer) o;

  for (Type forType : autowired.getAutowiredFor()) {

  //如果存在,都放到serializers缓存中

  put(forType, autowired);

  }

  }

  } catch (ClassCastException ex) {

  // skip

  }

  //尝试在缓存找序列化器

  writer = serializers.get(clazz);

  }

  //2.与第一种区别的地方在于加载器不同,此时尝试用加载JSON的classLoader。

  if (writer == null) {

  final ClassLoader classLoader = JSON.class.getClassLoader();

  if (classLoader != Thread.currentThread().getContextClassLoader()) {

  try {

  for (Object o : ServiceLoader.load(AutowiredObjectSerializer.class, classLoader)) {

  if (!(o instanceof AutowiredObjectSerializer)) {

  continue;

  }

  AutowiredObjectSerializer autowired = (AutowiredObjectSerializer) o;

  for (Type forType : autowired.getAutowiredFor()) {

  put(forType, autowired);

  }

  }

  } catch (ClassCastException ex) {

  // skip

  }

  writer = serializers.get(clazz);

  }

  }

  //3.当前这种是针对传进来的clazz的类型,去寻找对应的序列化器。

  //这里都是常用的一些类型,比如Map,List,Collection,Date,enum,Iterator等等。还有JSON相关的一些,JSONAware,JSONSerializable,JSONStreamAware 。

  //特殊处理,(1)java自带图形包java.awt (2)jdk8中的日期包、Optional、concurrent(3)oracle相关的类(4)springfox相关的类(5)guava框架中类

  if (writer == null) {

  String className = clazz.getName();

  Class superClass;

  if (Map.class.isAssignableFrom(clazz)) {

  put(clazz, writer = MapSerializer.instance);

  } else if (List.class.isAssignableFrom(clazz)) {

  put(clazz, writer = ListSerializer.instance);

  } else if (Collection.class.isAssignableFrom(clazz)) {

  put(clazz, writer = CollectionCodec.instance);

  } else if (Date.class.isAssignableFrom(clazz)) {

  put(clazz, writer = DateCodec.instance);

  } else if (JSONAware.class.isAssignableFrom(clazz)) {

  put(clazz, writer = JSONAwareSerializer.instance);

  } else if (JSONSerializable.class.isAssignableFrom(clazz)) {

  put(clazz, writer = JSONSerializableSerializer.instance);

  } else if (JSONStreamAware.class.isAssignableFrom(clazz)) {

  put(clazz, writer = MiscCodec.instance);

  } else if (clazz.isEnum()) {

  JSONType jsonType = TypeUtils.getAnnotation(clazz, JSONType.class);

  if (jsonType != null && jsonType.serializeEnumAsJavaBean()) {

  put(clazz, writer = createJavaBeanSerializer(clazz));

  } else {

  put(clazz, writer = EnumSerializer.instance);

  }

  } else if ((superClass = clazz.getSuperclass()) != null && superClass.isEnum()) {

  JSONType jsonType = TypeUtils.getAnnotation(superClass, JSONType.class);

  if (jsonType != null && jsonType.serializeEnumAsJavaBean()) {

  put(clazz, writer = createJavaBeanSerializer(clazz));

  } else {

  put(clazz, writer = EnumSerializer.instance);

  }

  } else if (clazz.isArray()) {

  Class componentType = clazz.getComponentType();

  ObjectSerializer compObjectSerializer = getObjectWriter(componentType);

  put(clazz, writer = new ArraySerializer(componentType, compObjectSerializer));

  } else if (Throwable.class.isAssignableFrom(clazz)) {

  SerializeBeanInfo beanInfo = TypeUtils.buildBeanInfo(clazz, null, propertyNamingStrategy);

  beanInfo.features |= SerializerFeature.WriteClassName.mask;

  put(clazz, writer = new JavaBeanSerializer(beanInfo));

  } else if (TimeZone.class.isAssignableFrom(clazz) || Map.Entry.class.isAssignableFrom(clazz)) {

  put(clazz, writer = MiscCodec.instance);

  } else if (Appendable.class.isAssignableFrom(clazz)) {

  put(clazz, writer = AppendableSerializer.instance);

  } else if (Charset.class.isAssignableFrom(clazz)) {

  put(clazz, writer = ToStringSerializer.instance);

  } else if (Enumeration.class.isAssignableFrom(clazz)) {

  put(clazz, writer = EnumerationSerializer.instance);

  } else if (Calendar.class.isAssignableFrom(clazz) //

  || XMLGregorianCalendar.class.isAssignableFrom(clazz)) {

  put(clazz, writer = CalendarCodec.instance);

  } else if (Clob.class.isAssignableFrom(clazz)) {

  put(clazz, writer = ClobSeriliazer.instance);

  } else if (TypeUtils.isPath(clazz)) {

  put(clazz, writer = ToStringSerializer.instance);

  } else if (Iterator.class.isAssignableFrom(clazz)) {

  put(clazz, writer = MiscCodec.instance);

  } else if (org.w3c.dom.Node.class.isAssignableFrom(clazz)) {

  put(clazz, writer = MiscCodec.instance);

  } else {

  if (className.startsWith("java.awt.") //

  && AwtCodec.support(clazz) //

  ) {

  // awt

  if (!awtError) {

  try {

  String[] names = new String[]{

  "java.awt.Color",

  "java.awt.Font",

  "java.awt.Point",

  "java.awt.Rectangle"

  };

  for (String name : names) {

  if (name.equals(className)) {

  put(Class.forName(name), writer = AwtCodec.instance);

  return writer;

  }

  }

  } catch (Throwable e) {

  awtError = true;

  // skip

  }

  }

  }

  // jdk8

  if ((!jdk8Error) //

  && (className.startsWith("java.time.") //

  || className.startsWith("java.util.Optional") //

  || className.equals("java.util.concurrent.atomic.LongAdder")

  || className.equals("java.util.concurrent.atomic.DoubleAdder")

  )) {

  try {

  {

  String[] names = new String[]{

  "java.time.LocalDateTime",

  "java.time.LocalDate",

  "java.time.LocalTime",

  "java.time.ZonedDateTime",

  "java.time.OffsetDateTime",

  "java.time.OffsetTime",

  "java.time.ZoneOffset",

  "java.time.ZoneRegion",

  "java.time.Period",

  "java.time.Duration",

  "java.time.Instant"

  };

  for (String name : names) {

  if (name.equals(className)) {

  put(Class.forName(name), writer = Jdk8DateCodec.instance);

  return writer;

  }

  }

  }

  {

  String[] names = new String[]{

  "java.util.Optional",

  "java.util.OptionalDouble",

  "java.util.OptionalInt",

  "java.util.OptionalLong"

  };

  for (String name : names) {

  if (name.equals(className)) {

  put(Class.forName(name), writer = OptionalCodec.instance);

  return writer;

  }

  }

  }

  {

  String[] names = new String[]{

  "java.util.concurrent.atomic.LongAdder",

  "java.util.concurrent.atomic.DoubleAdder"

  };

  for (String name : names) {

  if (name.equals(className)) {

  put(Class.forName(name), writer = AdderSerializer.instance);

  return writer;

  }

  }

  }

  } catch (Throwable e) {

  // skip

  jdk8Error = true;

  }

  }

  if ((!oracleJdbcError) //

  && className.startsWith("oracle.sql.")) {

  try {

  String[] names = new String[] {

  "oracle.sql.DATE",

  "oracle.sql.TIMESTAMP"

  };

  for (String name : names) {

  if (name.equals(className)) {

  put(Class.forName(name), writer = DateCodec.instance);

  return writer;

  }

  }

  } catch (Throwable e) {

  // skip

  oracleJdbcError = true;

  }

  }

  if ((!springfoxError) //

  && className.equals("springfox.documentation.spring.web.json.Json")) {

  try {

  put(Class.forName("springfox.documentation.spring.web.json.Json"), //

  writer = SwaggerJsonSerializer.instance);

  return writer;

  } catch (ClassNotFoundException e) {

  // skip

  springfoxError = true;

  }

  }

  if ((!guavaError) //

  && className.startsWith("com.google.common.collect.")) {

  try {

  String[] names = new String[] {

  "com.google.common.collect.HashMultimap",

  "com.google.common.collect.LinkedListMultimap",

  "com.google.common.collect.ArrayListMultimap",

  "com.google.common.collect.TreeMultimap"

  };

  for (String name : names) {

  if (name.equals(className)) {

  put(Class.forName(name), writer = GuavaCodec.instance);

  return writer;

  }

  }

  } catch (ClassNotFoundException e) {

  // skip

  guavaError = true;

  }

  }

  if ((!jsonnullError) && className.equals("net.sf.json.JSONNull")) {

  try {

  put(Class.forName("net.sf.json.JSONNull"), writer = MiscCodec.instance);

  return writer;

  } catch (ClassNotFoundException e) {

  // skip

  jsonnullError = true;

  }

  }

  //如果class实现唯一接口,并且接口包含注解,使用AnnotationSerializer序列化

  Class[] interfaces = clazz.getInterfaces();

  if (interfaces.length == 1 && interfaces[0].isAnnotation()) {

  put(clazz, AnnotationSerializer.instance);

  return AnnotationSerializer.instance;

  }

  //如果使用了cglib或者javassist动态代理

  if (TypeUtils.isProxy(clazz)) {

  //得到父类并获取父类的序列化器

  Class superClazz = clazz.getSuperclass();

  ObjectSerializer superWriter = getObjectWriter(superClazz);

  put(clazz, superWriter);

  return superWriter;

  }

  //如果是jdk自带的动态代理

  if (Proxy.isProxyClass(clazz)) {

  Class handlerClass = null;

  //如果继承两个接口,取第二个接口做为handlerClass

  if (interfaces.length == 2) {

  handlerClass = interfaces[1];

  } else {

  for (Class proxiedInterface : interfaces) {

  //spring切面相关的接口,跳过 if(proxiedInterface.getName().startsWith("org.springframework.aop.")) {

  continue;

  }

  //如果除了aop的有多个接口,则跳出,并置handlerClass为null

  if (handlerClass != null) {

  handlerClass = null; // multi-matched

  break;

  }

  handlerClass = proxiedInterface;

  }

  }

  //handlerClass不为null,作为父类寻找序列化器,作为当前类的序列化器

  if (handlerClass != null) {

  ObjectSerializer superWriter = getObjectWriter(handlerClass);

  put(clazz, superWriter);

  return superWriter;

  }

  }

  //如果开启,使用JavaBeanSerializer 序列化

  if (create) {

  writer = createJavaBeanSerializer(clazz);

  put(clazz, writer);

  }

  }

  if (writer == null) {

  writer = serializers.get(clazz);

  }

  }

  return writer;

  }

  当使用toJSONString()方法时,如果不添加参数,默认create时true。大部分时候,我们要序列化的对象都是自定义的对象,所以进入createJavaBeanSerializer方法中一探究竟:

  public final ObjectSerializer createJavaBeanSerializer(Class clazz) {

  SerializeBeanInfo beanInfo = TypeUtils.buildBeanInfo(clazz, null, propertyNamingStrategy, fieldBased);

  if (beanInfo.fields.length == 0 && Iterable.class.isAssignableFrom(clazz)) {

  return MiscCodec.instance;

  }

  return createJavaBeanSerializer(beanInfo);

  }

  TypeUtils.buildBeanInfo会创建一个SerializeBeanInfo对象,看一下它的几个参数:

  public static SerializeBeanInfo buildBeanInfo(Class beanType //

  , Map aliasMap //

  , PropertyNamingStrategy propertyNamingStrategy //

  , boolean fieldBased //

  ){

  ...

  }

  (1)Class beanType :class对象类型

  (2)Map aliasMap:序列化对象字段的map,配置的属性真正的名称。默认为null。

  (3)PropertyNamingStrategy propertyNamingStrategy:命名方式,“驼峰式”等

  (4)boolean fieldBased:判断走哪一种收集fieldInfo的方法

  理解完参数,再看下build的逻辑。代码比较长,我们拆开看:

  (1)jsonType:

  我们结合例子一起看一下,JSONType和JSONField都可以定制序列化,可以设置包含,忽略,也可以设置格式。

  //@JSONType(ignores ={"id", "sex"})

  //@JSONType(includes={"name","sex"})

  public class User {

  @JSONField(name = "ID", ordinal = 3, serializeUsing = UserIDValueSerializer.class)

  private Long id;

  @JSONField(serialize = false)

  private String name;

  @JSONField(serialize = true, ordinal = 2)

  private String sex;

  @JSONField(deserialize = false)

  private String address;

  @JSONField(deserialize = true)

  private String phone;

  // 配置date序列化和反序列使用yyyyMMdd日期格式

  @JSONField(format = "yyyyMMdd", ordinal = 1)

  private Date date;

  public Long getId() {

  return id;

  }

  public void setId(Long id) {

  this.id = id;

  }

  //get and set ...

  }

  //1.寻找当前class对象中,是否有JSONType注解

  //先查询当前类,如果没有,再查询元素上存在的所有注解,包括从父类继承的。

  JSONType jsonType = TypeUtils.getAnnotation(beanType,JSONType.class);

  String[] orders = null;

  final int features;

  String typeName = null, typeKey = null;

  if(jsonType != null){

  //获取序列化的顺序

  orders = jsonType.orders();

  typeName = jsonType.typeName();

  if(typeName.length() == 0){

  typeName = null;

  }

  //获取命名类型,分为四种,以“personName”为例

  //(1)CamelCase(personName) (2)PascalCase(PersonName)(3)SnakeCase(person_name)(4)KebabCase(person-name)

  PropertyNamingStrategy jsonTypeNaming = jsonType.naming();

  //如果不是默认的驼峰式,就说明用户设置了name属性,覆盖传进来的propertyNamingStrategy参数

  if (jsonTypeNaming != PropertyNamingStrategy.CamelCase) {

  propertyNamingStrategy = jsonTypeNaming;

  }

  // 形成新的features值。这里的位运算存储很有意思,是一种很高效的设计。

  features = SerializerFeature.of(jsonType.serialzeFeatures());

  //循环向上寻找父类,如果找到有父类设置了typeKey,赋给变量存下来

  for(Class supperClass = beanType.getSuperclass()

  ; supperClass != null && supperClass != Object.class

  ; supperClass = supperClass.getSuperclass()){

  JSONType superJsonType = TypeUtils.getAnnotation(supperClass,JSONType.class);

  if(superJsonType == null){

  break;

  }

  typeKey = superJsonType.typeKey();

  if(typeKey.length() != 0){

  break;

  }

  }

  //遍历寻找当前类实现的接口,如果找到有父类设置了typeKey,赋给变量存下来

  for(Class interfaceClass : beanType.getInterfaces()){

  JSONType superJsonType = TypeUtils.getAnnotation(interfaceClass,JSONType.class);

  if(superJsonType != null){

  typeKey = superJsonType.typeKey();

  if(typeKey.length() != 0){

  break;

  }

  }

  }

  if(typeKey != null && typeKey.length() == 0){

  typeKey = null;

  }

  } else{

  features = 0;

  }

  聊一下SerializerFeature这个枚举类:

  SerializerFeature(){

  mask = (1 << ordinal());

  }

  这个枚举类是把所有feature按照顺序,位偏移计算后,得到一个mask,作为当前feature的标记值。ordinal()的取值是0~Integer.MAX_VALUE。所以第一个枚举类的值是 1,第二个是"10",第三个是"100",依次类推,可以存31个枚举值。

  所以每一位代表一个特征值,1是有,0是无。一个int数就可以表示当前设置了哪些特征值。

  这种设计思路对项目开发是很有帮助的,毕竟位运算是最高效的运算。

  Q:算上@Deprecated的,已经有30个特征值了,万一以后多加了特征值该怎么存储呢,直接把mask改为long型么?

  接着看具体的解析:

  这里分为两种方式:(1)computeGettersWithFieldBase (2)computeGetters

  // fieldName,field ,先生成fieldName的快照,减少之后的findField的轮询

  Map fieldCacheMap = new HashMap();

  ParserConfig.parserAllFieldToCache(beanType, fieldCacheMap);

  //根据fieldBased判断走哪一个getter方法,默认是false。

  List fieldInfoList = fieldBased

  ? computeGettersWithFieldBase(beanType, aliasMap, false, propertyNamingStrategy) //

  : computeGetters(beanType, jsonType, aliasMap, fieldCacheMap, false, propertyNamingStrategy);

  FieldInfo[] fields = new FieldInfo[fieldInfoList.size()];

  fieldInfoList.toArray(fields);

  FieldInfo[] sortedFields;

  List sortedFieldList;

  if(orders != null && orders.length != 0){

  sortedFieldList = fieldBased

  ? computeGettersWithFieldBase(beanType, aliasMap, true, propertyNamingStrategy) //

  : computeGetters(beanType, jsonType, aliasMap, fieldCacheMap, true, propertyNamingStrategy);

  } else{

  sortedFieldList = new ArrayList(fieldInfoList);

  Collections.sort(sortedFieldList);

  }

  sortedFields = new FieldInfo[sortedFieldList.size()];

  sortedFieldList.toArray(sortedFields);

  if(Arrays.equals(sortedFields, fields)){

  sortedFields = fields;

  }

  return new SerializeBeanInfo(beanType, jsonType, typeName, typeKey, features, fields, sortedFields);

  先看一下computeGettersWithFieldBase方法:

  public static List computeGettersWithFieldBase(

  Class clazz, //

  Map aliasMap, //

  boolean sorted, //

  PropertyNamingStrategy propertyNamingStrategy){

  Map fieldInfoMap = new LinkedHashMap();

  for(Class currentClass = clazz; currentClass != null; currentClass = currentClass.getSuperclass()){

  Field[] fields = currentClass.getDeclaredFields();

  computeFields(currentClass, aliasMap, propertyNamingStrategy, fieldInfoMap, fields);

  }

  return getFieldInfos(clazz, sorted, fieldInfoMap);

  }

  配合上面的例子,来看computeFields方法是如何一步步解析的:

  private static void computeFields(

  Class clazz, //

  Map aliasMap, //

  PropertyNamingStrategy propertyNamingStrategy, //

  Map fieldInfoMap, //

  Field[] fields){

  for(Field field : fields){

  //获取属性的修饰符。如果是静态变量,则跳过,不放在fieldInfoMap中

  if(Modifier.isStatic(field.getModifiers())){

  continue;

  }

  //读取JSONField注解,解析序列化的定制化配置

  JSONField fieldAnnotation = field.getAnnotation(JSONField.class);

  //不小心发现一个拼写错误,“serialzeFeatures”。FieldInfo类里面的属性也是这个。强迫症患者。

  int ordinal = 0, serialzeFeatures = 0, parserFeatures = 0;

  String propertyName = field.getName();

  String label = null;

  if(fieldAnnotation != null){

  //依次解析注解的serialize、ordinal、serialzeFeatures、parserFeatures、propertyName、label属性,这个例子里可以看到

  if(!fieldAnnotation.serialize()){

  continue;

  }

  ordinal = fieldAnnotation.ordinal();

  serialzeFeatures = SerializerFeature.of(fieldAnnotation.serialzeFeatures());

  parserFeatures = Feature.of(fieldAnnotation.parseFeatures());

  if(fieldAnnotation.name().length() != 0){

  propertyName = fieldAnnotation.name();

  }

  if(fieldAnnotation.label().length() != 0){

  label = fieldAnnotation.label();

  }

  }

  //如果传入的aliasMap不为null,就用别名。如果别名为null,就直接跳过

  //Q:aliasMap会存放所有属性的别名么?如果不是,等于null就跳过,那这个属性就被抛弃了,不会放到fieldInfoMap中。

  if(aliasMap != null){

  propertyName = aliasMap.get(propertyName);

  if(propertyName == null){

  continue;

  }

  }

  //属性的命名策略,修改格式

  if(propertyNamingStrategy != null){

  propertyName = propertyNamingStrategy.translate(propertyName);

  }

  //生成FieldInfo,并放到map中

  if(!fieldInfoMap.containsKey(propertyName)){

  FieldInfo fieldInfo = new FieldInfo(propertyName, null, field, clazz, null, ordinal, serialzeFeatures, parserFeatures,

  null, fieldAnnotation, label);

  fieldInfoMap.put(propertyName, fieldInfo);

  }

  }

  }

  再看一下 computeGetters方法:

  public static List computeGetters(Class clazz, //

  JSONType jsonType, //

  Map aliasMap, //

  Map fieldCacheMap, //

  boolean sorted, //

  PropertyNamingStrategy propertyNamingStrategy //

  ){

  Map fieldInfoMap = new LinkedHashMap();

  boolean kotlin = TypeUtils.isKotlin(clazz);

  // for kotlin

  Constructor[] constructors = null;

  Annotation[][] paramAnnotationArrays = null;

  String[] paramNames = null;

  short[] paramNameMapping = null;

  Method[] methods = clazz.getMethods();

  for(Method method : methods){

  String methodName = method.getName();

  int ordinal = 0, serialzeFeatures = 0, parserFeatures = 0;

  String label = null;

  //对特殊情况的判断(序列化目标是寻找get方法)

  //(1)静态方法(2)返回类型是void(3)参数类型数组长度不是0.也就是存在参数(4)返回类类型是类加载器(5)groovy的MetaClass(6)异常处理getSuppressed(7)Kotlin类型

  if(Modifier.isStatic(method.getModifiers())){

  continue;

  }

  。。。

  /**

  * 如果在属性或者方法上存在JSONField注解,并且定制了name属性,不以类上的propertyNamingStrategy设置为准,以此字段的JSONField的name定制为准。

  */

  Boolean fieldAnnotationAndNameExists = false;

  //判断是否有JSONField注解

  JSONField annotation = method.getAnnotation(JSONField.class);

  if(annotation == null){

  annotation = getSuperMethodAnnotation(clazz, method);

  }

  //kotlin相关,不常用到

  if(annotation == null && kotlin){

  。。。

  }

  //如果有注解,读取注解中定义的name,feature等参数

  if(annotation != null){

  if(!annotation.serialize()){

  continue;

  }

  ordinal = annotation.ordinal();

  serialzeFeatures = SerializerFeature.of(annotation.serialzeFeatures());

  parserFeatures = Feature.of(annotation.parseFeatures());

  if(annotation.name().length() != 0){

  String propertyName = annotation.name();

  if(aliasMap != null){

  propertyName = aliasMap.get(propertyName);

  if(propertyName == null){

  continue;

  }

  }

  FieldInfo fieldInfo = new FieldInfo(propertyName, method, null, clazz, null, ordinal,

  serialzeFeatures, parserFeatures, annotation, null, label);

  fieldInfoMap.put(propertyName, fieldInfo);

  continue;

  }

  if(annotation.label().length() != 0){

  label = annotation.label();

  }

  }

  //常用方法,判断方法是否以“get”开头

  if(methodName.startsWith("get")){

  //排除特殊情况(1)长度<4(2)getClass (3)枚举类的getDeclaringClass

  if(methodName.length() < 4){

  continue;

  }

  if(methodName.equals("getClass")){

  continue;

  }

  if(methodName.equals("getDeclaringClass") && clazz.isEnum()){

  continue;

  }

  char c3 = methodName.charAt(3);

  String propertyName;

  //开始解析get方法,判断get之后的第一个字符c3

  //1、如果c3是大写,判断compatibleWithJavaBean属性(默认为false),

  //如果为true,截取get后的字符串,如果前两位都是大写,则直接返回;其他情况,把首字母变小写返回。

  //如果是false,直接把get后字符串的第一位变小写返回。

  //2.如果是'_','f'等特殊情况,按照各自规则截取。

  if(Character.isUpperCase(c3) //

  || c3 > 512 // for unicode method name

  ){

  if(compatibleWithJavaBean){

  propertyName = decapitalize(methodName.substring(3));

  } else{

  propertyName = Character.toLowerCase(methodName.charAt(3)) + methodName.substring(4);

  }

  //这里还有一个替换过程。还记得上面buildBeanInfo中生成的fieldCacheMap么,这里面存的是类得到的所有field。所以如果compatibleWithFieldName为true,代表按照field属性的大小写来,如果methodName的get方法之后的字符串在属性map里面,就用map中存好的属性。

  propertyName = getPropertyNameByCompatibleFieldName(fieldCacheMap, methodName, propertyName, 3);

  } else if(c3 == '_'){

  propertyName = methodName.substring(4);

  } else if(c3 == 'f'){

  propertyName = methodName.substring(3);

  } else if(methodName.length() >= 5 && Character.isUpperCase(methodName.charAt(4))){

  propertyName = decapitalize(methodName.substring(3));

  } else{

  continue;

  }

  //判断JSONType注解的includes 和 ignores 属性,如果是忽略的,跳过这个方法的属性检测。提一下,这里的比较是区分大小写的equals,所以设置includes 和 ignores,最好看看它上述的解析规则,否则属性设置未必生效。

  boolean ignore = isJSONTypeIgnore(clazz, propertyName);

  if(ignore){

  continue;

  }

  //假如bean的field很多的情况一下,轮询时将大大降低效率

  //假设现在得到的propertyName是“personName”,getFieldFromCache会从不同key尝试从fieldCacheMap获取field。(1)"_personName"(2)"m_personName"(3)"PersonName"(4) propertyName长度大于2且首字母小写,第二个字母大写的时候,忽略大小写从map中尝试获取。(不是很懂这个特殊逻辑)

  Field field = ParserConfig.getFieldFromCache(propertyName, fieldCacheMap);

  //如果还没获取到,且propertyName第二个字符是大写,再得到javaBeanCompatiblePropertyName,尝试从map中获取。

  if(field == null && propertyName.length() > 1){

  char ch = propertyName.charAt(1);

  if(ch >= 'A' && ch <= 'Z'){

  String javaBeanCompatiblePropertyName = decapitalize(methodName.substring(3));

  field = ParserConfig.getFieldFromCache(javaBeanCompatiblePropertyName, fieldCacheMap);

  }

  }

  JSONField fieldAnnotation = null;

  //检测这个field是否有设置属性

  if(field != null){

  fieldAnnotation = field.getAnnotation(JSONField.class);

  if(fieldAnnotation != null){

  if(!fieldAnnotation.serialize()){

  continue;

  }

  ordinal = fieldAnnotation.ordinal();

  serialzeFeatures = SerializerFeature.of(fieldAnnotation.serialzeFeatures());

  parserFeatures = Feature.of(fieldAnnotation.parseFeatures());

  if(fieldAnnotation.name().length() != 0){

  fieldAnnotationAndNameExists = true;

  propertyName = fieldAnnotation.name();

  if(aliasMap != null){

  propertyName = aliasMap.get(propertyName);

  if(propertyName == null){

  continue;

  }

  }

  }

  if(fieldAnnotation.label().length() != 0){

  label = fieldAnnotation.label();

  }

  }

  }

  //默认情况下,aliasMap为null

  if(aliasMap != null){

  propertyName = aliasMap.get(propertyName);

  if(propertyName == null){

  continue;

  }

  }

  //propertyNamingStrategy不为null,修改格式

  if(propertyNamingStrategy != null && !fieldAnnotationAndNameExists){

  propertyName = propertyNamingStrategy.translate(propertyName);

  }

  FieldInfo fieldInfo = new FieldInfo(propertyName, method, field, clazz, null, ordinal, serialzeFeatures, parserFeatures,

  annotation, fieldAnnotation, label);

  fieldInfoMap.put(propertyName, fieldInfo);

  }

  //如果是is开头的,是类似的逻辑。不再赘述

  if(methodName.startsWith("is")){

  。。。

  }

  }

  Field[] fields = clazz.getFields();

  //最后再调用computeFields方法

  computeFields(clazz, aliasMap, propertyNamingStrategy, fieldInfoMap, fields);

  return getFieldInfos(clazz, sorted, fieldInfoMap);

  }

  小结一下computeGetters方法的逻辑:

  (1)对特殊情况的判断(序列化目标是寻找get方法)

  (a)静态方法

  (b)返回类型是void

  (c)参数类型数组长度不是0.也就是存在参数

  (d)返回类类型是类加载器

  (e)groovy的MetaClass

  (f)异常处理getSuppressed

  (g)Kotlin类型

  (2) check当前的method是否有JSONField注解,并判断是否是kotlin相关的类。 (JSONField可以设置在属性上,也可以设置在方法上。)

  (3)“get”开头的解析。

  (a)排除特殊情况:长度<4;getClass ;枚举类的getDeclaringClass

  (b) 开始解析get方法,判断get之后的第一个字符c3。

  如果c3是大写,判断compatibleWithJavaBean属性(默认为false),如果为true,截取get后的字符串,如果前两位都 是大写,则直接返回;其他情况,把首字母变小写返回。 如果是false,直接把get后字符串的第一位变小写返回。如果是'_','f'等特殊情况,按照各自规则截取。

  这里还有一个替换过程。传进来的buildBeanInfo中生成的fieldCacheMap,这里面存的是类得到的所有field。所以如果compatibleWithFieldName为true,代表按照field属性的大小写来,如果methodName的get方法之后的字符串在属性map里面,就用map中存好的属性。

  fastJson在多处用了这种map,优化了查询的效率。

  (4)对得到field中的JSONField注解做解析。

  到这里,SerializeBeanInfo的步骤就基本完成了,接下来就是正式的去生成序列化器的方法createJavaBeanSerializer:

  在之前先提一下,fastjson内嵌了ASM框架来动态生成类,ASMClassLoader继承了java的类装载器ClassLoader。

  public ObjectSerializer createJavaBeanSerializer(SerializeBeanInfo beanInfo) {

  JSONType jsonType = beanInfo.jsonType;

  boolean asm = this.asm && !fieldBased;

  //jsonType注解不为null

  if (jsonType != null) {

  //jsonType中设置的序列化器属性,默认是Void.class

  Class serializerClass = jsonType.serializer();

  if (serializerClass != Void.class) {

  try {

  //如果是自己写的序列化器,继承了ObjectSerializer接口,直接返回用户设定的序列化器。

  Object seralizer = serializerClass.newInstance();

  if (seralizer instanceof ObjectSerializer) {

  return (ObjectSerializer) seralizer;

  }

  } catch (Throwable e) {

  // skip

  }

  }

  //jsonType设定了asm可用属性。

  if (jsonType.asm() == false) {

  asm = false;

  }

  if (asm) {

  //check:如果设置了下面的一些属性,即使asm可用,也设置为不可用。

  for (SerializerFeature feature : jsonType.serialzeFeatures()) {

  if (SerializerFeature.WriteNonStringValueAsString == feature //

  || SerializerFeature.WriteEnumUsingToString == feature //

  || SerializerFeature.NotWriteDefaultValue == feature

  || SerializerFeature.BrowserCompatible == feature) {

  asm = false;

  break;

  }

  }

  }

  if (asm) {

  //check:如果设置了过滤器,asm也禁用

  final Class[] filterClasses = jsonType.serialzeFilters();

  if (filterClasses.length != 0) {

  asm = false;

  }

  }

  }

  Class clazz = beanInfo.beanType;

  //如果bean是public的,直接用JavaBeanSerializer返回。

  if (!Modifier.isPublic(beanInfo.beanType.getModifiers())) {

  return new JavaBeanSerializer(beanInfo);

  }无锡人流多少钱 http://www.bhnfkyy.com/

  //(1)如果是类加载器在ASMClassLoader的外部(2)或者clazz就是 Serializable.class(3)clazz就是Object.class

  if (asm && asmFactory.classLoader.isExternalClass(clazz)

  || clazz == Serializable.class || clazz == Object.class) {

  asm = false;

  }

  //不符合asm的命名规则

  if (asm && !ASMUtils.checkName(clazz.getSimpleName())) {

  asm = false;

  }

  //接口

  if (asm && beanInfo.beanType.isInterface()) {

  asm = false;

  }

  if (asm) {

  //对每一个属性做check

  for(FieldInfo fieldInfo : beanInfo.fields){

  Field field = fieldInfo.field;

  if (field != null && !field.getType().equals(fieldInfo.fieldClass)) {

  asm = false;

  break;

  }

  Method method = fieldInfo.method;

  if (method != null && !method.getReturnType().equals(fieldInfo.fieldClass)) {

  asm = false;

  break;

  }

  JSONField annotation = fieldInfo.getAnnotation();

  if (annotation == null) {

  continue;

  }

  String format = annotation.format();

  if (format.length() != 0) {

  if (fieldInfo.fieldClass == String.class && "trim".equals(format)) {

  } else {

  asm = false;

  break;

  }

  }

  if ((!ASMUtils.checkName(annotation.name())) //

  || annotation.jsonDirect()

  || annotation.serializeUsing() != Void.class

  || annotation.unwrapped()

  ) {

  asm = false;

  break;

  }

  for (SerializerFeature feature : annotation.serialzeFeatures()) {

  if (SerializerFeature.WriteNonStringValueAsString == feature //

  || SerializerFeature.WriteEnumUsingToString == feature //

  || SerializerFeature.NotWriteDefaultValue == feature

  || SerializerFeature.BrowserCompatible == feature

  || SerializerFeature.WriteClassName == feature) {

  asm = false;

  break;

  }

  }

  if (TypeUtils.isAnnotationPresentOneToMany(method) || TypeUtils.isAnnotationPresentManyToMany(method)) {

  asm = false;

  break;

  }

  }

  }

  if (asm) {

  try {

  ObjectSerializer asmSerializer = createASMSerializer(beanInfo);

  if (asmSerializer != null) {

  return asmSerializer;

  }

  } catch (ClassNotFoundException ex) {

  // skip

  } catch (ClassFormatError e) {

  // skip

  } catch (ClassCastException e) {

  // skip

  } catch (OutOfMemoryError e) {

  if (e.getMessage().indexOf("Metaspace") != -1) {

  throw e;

  }

  // skip

  } catch (Throwable e) {

  throw new JSONException("create asm serializer error, verson " + JSON.VERSION + ", class " + clazz, e);

  }

  }

  return new JavaBeanSerializer(beanInfo);

  }

  两种得到序列化器的方法:(1)JavaBeanSerializer(2)createASMSerializer

  使用asm的条件:

  (1)JSONType注解设置了asm的属性为不可用

  (2)SerializerFeature设置某些序列化属性,WriteNonStringValueAsString、WriteEnumUsingToString、NotWriteDefaultValue、BrowserCompatible。

  (3)如果设置了过滤器,asm也禁用 。

  (4)该clazz为非public类

  (5) 该clazz的类加载器在ASMClassLoader的外部、clazz是Serializable.class或者Object.class

  (6)不符合asm的命名规则、bean是接口类型

  (7)对每一个field属性的check,如果不满足条件也禁用asm。

fastjson源码分析之序列化的更多相关文章

  1. Hadoop2源码分析-序列化篇

    1.概述 上一篇我们了解了MapReduce的相关流程,包含MapReduce V2的重构思路,新的设计架构,与MapReduce V1的区别等内容,今天我们在来学习下在Hadoop V2中的序列化的 ...

  2. 【Zookeeper】源码分析之序列化

    一.前言 在完成了前面的理论学习后,现在可以从源码角度来解析Zookeeper的细节,首先笔者想从序列化入手,因为在网络通信.数据存储中都用到了序列化,下面开始分析. 二.序列化 序列化主要在zook ...

  3. cvb源码分析,resful规范,drf,drf序列化组件,95

    1 CBV的源码分析 -Class Base View(基于类的视图) -Function Base View(基于函数的视图) -def as_view 类方法 -def view:类方法内部,闭包 ...

  4. 【Zookeeper】源码分析目录

    Zookeeper源码分析目录如下 1. [Zookeeper]源码分析之序列化 2. [Zookeeper]源码分析之持久化(一)之FileTxnLog 3. [Zookeeper]源码分析之持久化 ...

  5. Hadoop2源码分析-RPC探索实战

    1.概述 在<Hadoop2源码分析-RPC机制初识>博客中,我们对RPC机制有了初步的认识和了解,下面我们对Hadoop V2的RPC机制做进一步探索,在研究Hadoop V2的RPC机 ...

  6. Hadoop2源码分析-RPC机制初识

    1.概述 上一篇博客,讲述Hadoop V2的序列化机制,这为我们学习Hadoop V2的RPC机制奠定了基础.RPC的内容涵盖的信息有点多,包含Hadoop的序列化机制,RPC,代理,NIO等.若对 ...

  7. 12.源码分析—如何为SOFARPC写一个序列化?

    SOFARPC源码解析系列: 1. 源码分析---SOFARPC可扩展的机制SPI 2. 源码分析---SOFARPC客户端服务引用 3. 源码分析---SOFARPC客户端服务调用 4. 源码分析- ...

  8. 【源码分析】FastJson全局配置日期格式导致@JSONField(format = "yyyy-MM-dd")注解失效

    出现的问题 我全局配置的时间格式是:yyyy-MM-dd HH:mm:ss @JSONField注解配置的时间格式是:yyyy-MM-dd 最终的返回结果是:yyyy-MM-dd HH:mm:ss 问 ...

  9. Django drf:序列化增删改查、局部与全局钩子源码流程、认证源码分析、执行流程

    一.序列化类的增.删.改.查 用drf的序列化组件   -定义一个类继承class BookSerializer(serializers.Serializer):   -写字段,如果不指定source ...

随机推荐

  1. Mysql按日、周、月进行分组统计

    我们在用 Mysql 制作数据可视化图表时候,经常需要按照天.周.月等不同的粒度对数据进行分组统计.而我们的时间可能是 “2017/12/5 0:0:0” 这种准确的时间. 所以在进行分组之前我们需要 ...

  2. chartjs

    chartjs是一个图表控件集合,使用html5的canvas进行绘制. 官网:http://www.chartjs.org/ 文档:https://www.chartjs.org/docs/late ...

  3. 解决electron-vue中无法Element的Tooltip组件

    打开文件:electron-vue/webpack.renderer.config.js 在大约21行左右找到 let whiteListedModules 将element-ui添加进去,最终如下所 ...

  4. 随便贴两个漏洞,如 Apache JServ协议服务

    1.Apache JServ协议服务 描述:Apache JServ协议(AJP)是一种二进制协议,可以将来自Web服务器的入站请求代理到 位于Web服务器后面的应用程序服务器.不建议在互联网上公开使 ...

  5. Spark布隆过滤器(bloomFilter)

    数据过滤在很多场景都会应用到,特别是在大数据环境下.在数据量很大的场景实现过滤或者全局去重,需要存储的数据量和计算代价是非常庞大的.很多小伙伴第一念头肯定会想到布隆过滤器,有一定的精度损失,但是存储性 ...

  6. RabbitMQ整合Spring Booot【点对点模式】

    pom.xml: <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www. ...

  7. 【446】Deep Learning

    ref: 深度学习基础介绍 机器学习19 神经网络NN算法 ref: 深度学习基础介绍 机器学习11 神经网络算法应用上 ref: 深度学习基础介绍 机器学习12 神经网络算法应用下 ref: 神经网 ...

  8. LODOP设置某打印项锁定下边距

    LODOP中的打印项定位都是按照top值(顶边距),left(左边距)来决定的 ,不能直接设置某打印项的下边距.此外,打印项的位置还受PRINT_INTA的前两个整体偏移值,打印机可打区域的影响.该文 ...

  9. PCL贪婪投影三角化算法

    贪婪投影三角化算法是一种对原始点云进行快速三角化的算法,该算法假设曲面光滑,点云密度变化均匀,不能在三角化的同时对曲面进行平滑和孔洞修复. 方法: (1)将三维点通过法线投影到某一平面 (2)对投影得 ...

  10. PCL

    PCL(PointCloudLibrary)——是一个的模块化的现代C++模板库. 其基于以下第三方库:Boost.Eigen.FLANN.VTK.CUDA.OpenNI.Qhull,实现点云相关的获 ...