文档章节

fastjson序列化原理详解

拉风小野驴
 拉风小野驴
发布于 2016/03/11 10:58
字数 2057
阅读 1859
收藏 0

所有序列化的API都在JSON类中,方法名称为toJSONString,或者我们也可以设计自己的序列化方法,代码如下:

public class MyJSON {

	
	public static String toJSONString(Object object, SerializeConfig config, SerializeFilter[] filters,
			SerializerFeature[] features) {
		SerializeWriter out = new SerializeWriter();

		try {
			// SerializeConfig可以理解为一个Map<Type,ObjectSerializer>,
			// 内部保存着类型与对应的对象序列化器之间的映射关系
			if (config == null)
				config = SerializeConfig.getGlobalInstance();
			// 核心序列化器,主要负责调用SerializeConfig根据value选择合适的对象序列化器
			// 内部还保存着输出流对象,以及各种过滤器
			JSONSerializer serializer = new JSONSerializer(out, config);
			// 所有特性最终会合成为一个int值,保存在输出流对象中
			if (features != null)
				for (SerializerFeature feature : features) {
					serializer.config(feature, true);
				}
			// 如上面所说,过滤器保存在核心序列化器中
			if (filters != null && filters.length > 0)
				setFilter(serializer, filters);
			// 序列化过程的入口方法
			serializer.write(object);

			return out.toString();
		} finally {
			out.close();
		}
	}

	private static void setFilter(JSONSerializer serializer, SerializeFilter... filters) {
		for (SerializeFilter filter : filters) {
			setFilter(serializer, filter);
		}
	}

	private static void setFilter(JSONSerializer serializer, SerializeFilter filter) {
		if (filter == null) {
			return;
		}

		if (filter instanceof PropertyPreFilter) {
			serializer.getPropertyPreFilters().add((PropertyPreFilter) filter);
		}

		if (filter instanceof NameFilter) {
			serializer.getNameFilters().add((NameFilter) filter);
		}

		if (filter instanceof ValueFilter) {
			serializer.getValueFilters().add((ValueFilter) filter);
		}

		if (filter instanceof PropertyFilter) {
			serializer.getPropertyFilters().add((PropertyFilter) filter);
		}

		if (filter instanceof BeforeFilter) {
			serializer.getBeforeFilters().add((BeforeFilter) filter);
		}

		if (filter instanceof AfterFilter) {
			serializer.getAfterFilters().add((AfterFilter) filter);
		}

		if (filter instanceof LabelFilter) {
			serializer.getLabelFilters().add((LabelFilter) filter);
		}
	}
}

调用方法时需要传入一个要序列化的目标对象object,以及三个可选参数,分别为SerializeConfig、SerializeFilter[]、SerializerFeature[]。这三个参数之所以为可选,是因为它们均有默认配置。

  1. SerializeConfig:序列化配置,我们可以把它理解为一个Map<Class,ObjectSerializer>,它的内部保存着所有被序列化对象的类型,与序列化此对象要使用的ObjectSerializer序列化器之间的映射关系。另外,如果遇到不存在的javaBean类型,它的内部还可以自动创建JavaBeanSerializer(包括直接创建JavaBeanSerializer对象,或者通过asm框架创建ASMJavaBeanSerializer的子类对象)。

  2. SerializeFilter:序列化过滤器???

  3. SerializerFeature:序列化器特性,主要用于控制序列化过程中的一些行为特性

序列化过程的入口其实就是serializer.write(object);方法的调用,具体执行过程如下:

public final void write(Object object) {
		// 如果value为null则直接输出"null"并返回
		if (object == null) {
			out.writeNull();
			return;
		}
		// 获取value对象的类型
		Class<?> clazz = object.getClass();
		// 根据Class类型,从SerializeConfig中选择合适的ObjectSerializer
		ObjectSerializer writer = getObjectWriter(clazz);

		try {
			// 调用ObjectSerializer序列化这个value
			// 因为输入的初始value对象没有与之对应的字段名称,
			// 因此第三(字段名称)和第四(字段类型)两个参数为null
			writer.write(this, object, null, null, 0);
		} catch (IOException e) {
			throw new JSONException(e.getMessage(), e);
		}
	}

这就是为什么我说JSONSerializer只负责调用SerializeConfig选择合适的ObjectSerializer进行序列化的原因。


因此,我们需要关注的重点有三个:

  1. fastjson内部有多少种对象序列化器(即ObjectSerializer有多少个实现类)?

  2. 每种对象序列化器是如何工作的?

  3. SerializeConfig中有多少种类型与对象序列化器之间的映射关系

ObjectSerializer接口类图如下:(点击可查看放大后的清晰图片)

整个体系共计61个实现类,以及一个子接口(AutowiredObjectSerializer)

具体每种对象序列化器如何工作,我会单开专题讲解

在SerializeConfig的构造方法中,会添加许多默认支持的映射关系,每个新创建的SerializeConfig对象,都会支持这些类型的序列化。

                put(Boolean.class, BooleanCodec.instance);
		put(Character.class, CharacterCodec.instance);
		put(Byte.class, IntegerCodec.instance);
		put(Short.class, IntegerCodec.instance);
		put(Integer.class, IntegerCodec.instance);
		put(Long.class, LongCodec.instance);
		put(Float.class, FloatCodec.instance);
		put(Double.class, DoubleSerializer.instance);
		put(BigDecimal.class, BigDecimalCodec.instance);
		put(BigInteger.class, BigIntegerCodec.instance);
		put(String.class, StringCodec.instance);
		put(byte[].class, ByteArraySerializer.instance);
		put(short[].class, ShortArraySerializer.instance);
		put(int[].class, IntArraySerializer.instance);
		put(long[].class, LongArraySerializer.instance);
		put(float[].class, FloatArraySerializer.instance);
		put(double[].class, DoubleArraySerializer.instance);
		put(boolean[].class, BooleanArraySerializer.instance);
		put(char[].class, CharArraySerializer.instance);
		put(Object[].class, ObjectArraySerializer.instance);
		put(Class.class, ClassSerializer.instance);

		put(SimpleDateFormat.class, DateFormatSerializer.instance);
		put(Locale.class, LocaleCodec.instance);
		put(Currency.class, CurrencyCodec.instance);
		put(TimeZone.class, TimeZoneCodec.instance);
		put(UUID.class, UUIDCodec.instance);
		put(InetAddress.class, InetAddressCodec.instance);
		put(Inet4Address.class, InetAddressCodec.instance);
		put(Inet6Address.class, InetAddressCodec.instance);
		put(InetSocketAddress.class, InetSocketAddressCodec.instance);
		put(File.class, FileCodec.instance);
		put(URI.class, URICodec.instance);
		put(URL.class, URLCodec.instance);
		put(Appendable.class, AppendableSerializer.instance);
		put(StringBuffer.class, AppendableSerializer.instance);
		put(StringBuilder.class, AppendableSerializer.instance);
		put(Pattern.class, PatternCodec.instance);
		put(Charset.class, CharsetCodec.instance);

		// atomic
		put(AtomicBoolean.class, AtomicBooleanSerializer.instance);
		put(AtomicInteger.class, AtomicIntegerSerializer.instance);
		put(AtomicLong.class, AtomicLongSerializer.instance);
		put(AtomicReference.class, ReferenceCodec.instance);
		put(AtomicIntegerArray.class, AtomicIntegerArrayCodec.instance);
		put(AtomicLongArray.class, AtomicLongArrayCodec.instance);
		
		put(WeakReference.class, ReferenceCodec.instance);
		put(SoftReference.class, ReferenceCodec.instance);

		// awt
		if (!awtError) {
    		try {
    			put(Class.forName("java.awt.Color"), ColorCodec.instance);
    			put(Class.forName("java.awt.Font"), FontCodec.instance);
    			put(Class.forName("java.awt.Point"), PointCodec.instance);
    			put(Class.forName("java.awt.Rectangle"),
    					RectangleCodec.instance);
    		} catch (Throwable e) {
    		    awtError = true;
    			// skip
    		}
		}
		
		// jdk8
		if (!jdk8Error) {
    		try {
    		    put(Class.forName("java.time.LocalDateTime"), Jdk8DateCodec.instance);
    		    put(Class.forName("java.time.LocalDate"), Jdk8DateCodec.instance);
    		    put(Class.forName("java.time.LocalTime"), Jdk8DateCodec.instance);
    		    put(Class.forName("java.time.ZonedDateTime"), Jdk8DateCodec.instance);
    		    put(Class.forName("java.time.OffsetDateTime"), Jdk8DateCodec.instance);
    		    put(Class.forName("java.time.OffsetTime"), Jdk8DateCodec.instance);
    		    put(Class.forName("java.time.ZoneOffset"), Jdk8DateCodec.instance);
    		    put(Class.forName("java.time.ZoneRegion"), Jdk8DateCodec.instance);
    		    put(Class.forName("java.time.Period"), Jdk8DateCodec.instance);
    		    put(Class.forName("java.time.Duration"), Jdk8DateCodec.instance);
    		    put(Class.forName("java.time.Instant"), Jdk8DateCodec.instance);
    		} catch (Throwable e) {
    		    // skip
    		    jdk8Error = true;
    		}
		}
		
		if (!oracleJdbcError) {
		    try {
                put(Class.forName("oracle.sql.DATE"), DateSerializer.instance);
                put(Class.forName("oracle.sql.TIMESTAMP"), DateSerializer.instance);
            } catch (Throwable e) {
                // skip
                oracleJdbcError = true;
            }
		}

因此,fastjson预定义的ObjectSerializer可识别的类型包括:

  1. 基本类型包装类:Boolean、Character、Byte、Short、Integer、Long、Float、Double

  2. 高精度数:BigDecimal、BigInteger

  3. String

  4. 基本类型的数组:boolean[]、char[]、byte[]、short[]、int[]、long[]、float[]、double[]

  5. Object[]、Class、SimpleDateFormat、Locale、Currency、TimeZone、UUID、InetAddress、Inet4Address、Inet6Address、InetSocketAddress、File、URI、URL、Appendable、StringBuffer、StringBuilder、Pattern、Charset

  6. 原子性对象:AtomicBoolean、AtomicInteger、AtomicLong、AtomicReference、AtomicIntegerArray、AtomicLongArray

  7. 引用对象:WeakReference、SoftReference

  8. awt相关类型:java.awt.Color、java.awt.Font、java.awt.Point、java.awt.Rectangle

  9. jdk8特有类型(java.time包中):LocalDateTime、LocalDate、LocalTime、ZonedDateTime、OffsetDateTime、OffsetTime、ZoneOffset、ZoneRegion、Period、Duration、Instant

  10. oracle特有类型(oracle.sql包中):DATE、TIMESTAMP

另外,fastjson还可以识别一些类型,不光可以识别这些类型,还可以识别这些类型的所有子类。由于不确定这些类具体有多少子类,不可能提前把这些子类的Class对象都添加到map中。因此采取的是,只要某一类型是这些可识别类型或其子类,则即时添加到SerializeConfig中。举个例子:fastjson可以识别所有Map接口的实现类,但不可能提前知道我们自定义的Map接口实现类(如:MyMap.class),所以当遇到这个自定义实现类的时候,才把映射关系添加到map中。

这些可识别的类型包括:

  1. Map接口及其实现类

  2. List接口及其实现类

  3. Collection接口及其实现类

  4. Date及其子类

  5. JSONAware及其实现类

  6. JSONSerializable接口及其实现类

  7. JSONStreamAware接口及其实现类

  8. 枚举类型及其子类

  9. 数组类型

  10. Throwable及其子类

  11. TimeZone及其子类

  12. Appendable及其子类

  13. Charset及其子类

  14. Enumeration及其子类

  15. Calendar及其子类

  16. Clob及其子类

除了以上提到的这些所有类型外,其他类型全部为不可识别类型。对于不可识别的类型,全部使用JavaBeanSerializer或者ASMJavaBeanSerializer的子类(asm动态生成)进行序列化。


SerializeConfig选择序列化器的逻辑如下:

public ObjectSerializer getObjectWriter(Class<?> clazz) {
		// 从已存在的映射关系中,查找序列化器
		ObjectSerializer writer = get(clazz);
		// 如果没有找到
		if (writer == null) {
			try {
				// 获取当前线程使用的类加载器
				final ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
				// 使用类加载器尝试加载"META-INF/services/com.alibaba.fastjson.serializer.AutowiredObjectSerializer"
				// 这个文件中保存的所有类(一行一个类的全限定名),并调用无参构造创建对象
				for (Object o : ServiceLoader.load(AutowiredObjectSerializer.class, classLoader)) {
					// 如果该类没有实现AutowiredObjectSerializer则忽略
					if (!(o instanceof AutowiredObjectSerializer)) {
						continue;
					}

					AutowiredObjectSerializer autowired = (AutowiredObjectSerializer) o;
					// 把这个序列化器可以处理的类型集合添加到map中
					for (Type forType : autowired.getAutowiredFor()) {
						put(forType, autowired);
					}
				}
			} catch (ClassCastException ex) {
				// skip
			}
			// 再次尝试获取对象序列化器
			writer = get(clazz);
		}
		// 如果还是没有找到
		if (writer == null) {
			// 获取加载JSON类的类加载器
			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 = get(clazz);
			}
		}
		// 如果仍找不到,则进行下面的逻辑处理
		if (writer == null) {
			if (Map.class.isAssignableFrom(clazz)) {
				put(clazz, MapSerializer.instance);
			} else if (List.class.isAssignableFrom(clazz)) {
				put(clazz, ListSerializer.instance);
			} else if (Collection.class.isAssignableFrom(clazz)) {
				put(clazz, CollectionSerializer.instance);
			} else if (Date.class.isAssignableFrom(clazz)) {
				put(clazz, DateSerializer.instance);
			} else if (JSONAware.class.isAssignableFrom(clazz)) {
				put(clazz, JSONAwareSerializer.instance);
			} else if (JSONSerializable.class.isAssignableFrom(clazz)) {
				put(clazz, JSONSerializableSerializer.instance);
			} else if (JSONStreamAware.class.isAssignableFrom(clazz)) {
				put(clazz, JSONStreamAwareSerializer.instance);
			} else if (clazz.isEnum() || (clazz.getSuperclass() != null && clazz.getSuperclass().isEnum())) {
				put(clazz, EnumSerializer.instance);
			} else if (clazz.isArray()) {
				Class<?> componentType = clazz.getComponentType();
				ObjectSerializer compObjectSerializer = getObjectWriter(componentType);
				put(clazz, new ArraySerializer(componentType, compObjectSerializer));
			} else if (Throwable.class.isAssignableFrom(clazz)) {
				put(clazz, new ExceptionSerializer(clazz));
			} else if (TimeZone.class.isAssignableFrom(clazz)) {
				put(clazz, TimeZoneCodec.instance);
			} else if (Appendable.class.isAssignableFrom(clazz)) {
				put(clazz, AppendableSerializer.instance);
			} else if (Charset.class.isAssignableFrom(clazz)) {
				put(clazz, CharsetCodec.instance);
			} else if (Enumeration.class.isAssignableFrom(clazz)) {
				put(clazz, EnumerationSeriliazer.instance);
			} else if (Calendar.class.isAssignableFrom(clazz)) {
				put(clazz, CalendarCodec.instance);
			} else if (Clob.class.isAssignableFrom(clazz)) {
				put(clazz, ClobSeriliazer.instance);
			} else {
				boolean isCglibProxy = false;
				boolean isJavassistProxy = false;
				for (Class<?> item : clazz.getInterfaces()) {
					if (item.getName().equals("net.sf.cglib.proxy.Factory")
							|| item.getName().equals("org.springframework.cglib.proxy.Factory")) {
						isCglibProxy = true;
						break;
					} else if (item.getName().equals("javassist.util.proxy.ProxyObject")) {
						isJavassistProxy = true;
						break;
					}
				}

				if (isCglibProxy || isJavassistProxy) {
					Class<?> superClazz = clazz.getSuperclass();

					ObjectSerializer superWriter = getObjectWriter(superClazz);
					put(clazz, superWriter);
					return superWriter;
				}

				if (Proxy.isProxyClass(clazz)) {
					put(clazz, createJavaBeanSerializer(clazz));
				} else {
					put(clazz, createJavaBeanSerializer(clazz));
				}
			}

			writer = get(clazz);
		}
		return writer;
	}


© 著作权归作者所有

拉风小野驴
粉丝 62
博文 24
码字总数 26595
作品 0
昌平
高级程序员
私信 提问
fastjson1.2.8原理

fastjson是阿里巴巴的项目,用于进行java对象与JSON字符串之间的序列化(对象转JSON)和反序列化(JSON转对象)。 所以fastjson分为序列化和反序列化两大核心功能,所有API都几种在JSON类中(...

拉风小野驴
2016/03/11
161
0
Fastjson - 详解SerializeFilter,格式化对象字段

遇到一个奇葩场景,维护一个老的程序, 应用换了个服务方. 要切接口. 但有以下问题. 接口逻辑稍有不同 , 需要自己按原接口文档,重组逻辑. 接口字段名,字段类型改动较大. 但还要按原接口文档返回...

ol_O_O_lo
2018/09/21
596
0
.NET高级代码审计(第三课)Fastjson反序列化漏洞

0X00 前言 Java中的Fastjson曾经爆出了多个反序列化漏洞和Bypass版本,而在.Net领域也有一个Fastjson的库,作者官宣这是一个读写Json效率最高的的.Net 组件,使用内置方法JSON.ToJSON可以快速...

Ivan1ee
03/22
0
0
dong/Dubbo 通用RPC调用组件

项目介绍 随着微服务的流行,不管是企业级应用还是互联网应用都在向微服务架构转变,我们在享用微服务给我们带来价值的同时,也发现了传统的开发模式上微服务给我们带来的管理、部署的问题,...

dong
2018/07/16
0
0
浅谈Java中JSON的序列化问题

在Java Web开发的过程中,时常会遇到与自己预期不一样的情况。有的时候静下心来自己去研究一番内在的原因还是很有趣的。这两天在写java web的时候,碰到了一个对象序列化的问题,问题大概是这...

小欣妹妹
2017/10/24
43
0

没有更多内容

加载失败,请刷新页面

加载更多

Nginx 快速安装详解

一、Nginx Nginx (engine x) 是一个高性能的HTTP和反向代理web服务器,同时也提供了IMAP/POP3/SMTP服务。Nginx是由伊戈尔·赛索耶夫为俄罗斯访问量第二的Rambler.ru站点(俄文:Рамбле...

网络小虾米
5分钟前
3
0
技术分享 | slave_relay_log_info 表认知的一些展开

作者:胡呈清 slave_relay_log_info 表是这样的: mysql> select * from mysql.slave_relay_log_info\G *************************** 1. row *************************** Number_of_lin......

爱可生
8分钟前
2
0
nginx配置http访问自动跳转到https

server {listen 80;server_name www.域名.com;rewrite ^(.*) https://$server_name$1 permanent;}server {listen 443;server_name www.域名.com;root /home/www;ssl on;......

很好亦平凡ms
8分钟前
2
0
SpreadJS:一款中国研发的类Excel开发工具,功能涵盖Excel的 95% 以上

Excel 作为一款深受用户喜爱的电子表格工具,借助其直观的界面、出色的计算性能、数据分析和图表,已经成为数据统计领域不可或缺的软件之一。 基于Excel对数据处理与分析的卓越表现,把Excel...

葡萄城技术团队
8分钟前
2
0
用javafx框架tornadofx做了个天气预报的程序

class WeatherApp : App(WeatherView::class)class WeatherView : View("十五天天气预报") { val weatherVM: WeatherViewModel by inject() val controller: WeatherController by......

oschina4cyy
12分钟前
2
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部