JsonFactory的Feature
除了JsonGenerator和JsonParser有Feature来控制行为外,JsonFactory也有自己的Feature特征,来控制自己的行为,可以理解为它对读/写均生效。
同样的也是一个内部枚举类:
public enum Feature { INTERN_FIELD_NAMES(true), CANONICALIZE_FIELD_NAMES(true), FAIL_ON_SYMBOL_HASH_OVERFLOW(true), USE_THREAD_LOCAL_FOR_BUFFER_RECYCLING(true) }
小贴士:枚举值均为bool类型,括号内为默认值
每个枚举值都控制着JsonFactory不同的行为。
INTERN_FIELD_NAMES(true)
这是Jackson所谓的key缓存:对JSON的字段名是否调用String#intern方法,放进字符串常量池里,以提高效率,默认是true。
小贴士:Jackson在调用String#intern之前使用InternCache(继承自ConcurrentHashMap)挡了一层,以防止高并发条件下intern效果不显著问题
intern()方法的作用这个老生常谈的话题了,解释为:当调用intern方法时,如果字符串池已经包含一个等于此String对象的字符串(内容相等),则返回池中的字符串。否则,将此 String放进池子里。下面写个例子增加感受感受:
@Test public void test2() { String str1 = "a"; String str2 = "b"; String str3 = "ab"; String str4 = str1 + str2; String str5 = new String("ab"); System.out.println(str5.equals(str3)); // true System.out.println(str5 == str3); // false // str5.intern()去常量池里找到了ab,所以直接返回常量池里的地址值了,因此是true System.out.println(str5.intern() == str3); // true System.out.println(str5.intern() == str4); // false }
想而知,开启这个小功能的意义还是蛮大的。因为同一个格式的JSON串被多次解析的可能性是非常之大的,想想你的Rest API接口,被调用多少次就会进行了多少次JSON解析(想想高并发场景)。这是一种用空间换时间的思想,所以小小功能,大大能量。
小贴士:如果你的应用对内存很敏感,你可以关闭此特征。但,真的有这种应用吗?有吗?
值得注意的是:此特征必须是CANONICALIZE_FIELD_NAMES也为true(开启)的情况下才有效,否则是无效的。
CANONICALIZE_FIELD_NAMES(true)
是否需要规范化属性名。所谓的规范化处理,就是去字符串池里尝试找一个字符串出来,默认值为true。规范化借助的是ByteQuadsCanonicalizer去处理,简而言之会根据Hash值来计算每个属性名存放的位置~
小贴士:ByteQuadsCanonicalizer拥有一套优秀的Hash算法来规范化属性存储,提高效率,抵御攻击(见下特征)
此特征开启了,INTERN_FIELD_NAMES特征的开启才有意义~
FAIL_ON_SYMBOL_HASH_OVERFLOW(true)
当ByteQuadsCanonicalizer处理hash碰撞达到一个阈值时,是否快速失败。
什么时候能达到阈值?官方的说明是:若触发了阈值,这基本可以确定是Dos(denial-of-service)攻击,制造了非常多的相同Hash值的key,这在正常情况下几乎是没有发生的可能性的。
所以,开启此特征值,可以防止攻击,在提高性能的同时也确保了安全。
USE_THREAD_LOCAL_FOR_BUFFER_RECYCLING(true)
是否使用BufferRecycler、ThreadLocal、SoftReference来有效的重用底层的输入/输出缓冲区。这个特性在后端服务(JavaEE)环境下是很有意义的,提效明显。但是对于在Android环境下就不见得了~
总而言之言而总之,JsonFactory的这几个特征值都建议开启,也就是维持默认即可。
定制读/写实例
读写行为的控制是通过各自的Feature来控制的,JsonFactory作为一个功能并非单一的工厂类,需要既能够定制化读JsonParser,也能定制化写JsonGenerator。
为此,对应的API它都提供了三份(一份定制化自己的Feature):
public JsonFactory enable(JsonFactory.Feature f); public JsonFactory enable(JsonParser.Feature f); public JsonFactory enable(JsonGenerator.Feature f); public JsonFactory disable(JsonFactory.Feature f); public JsonFactory disable(JsonParser.Feature f); public JsonFactory disable(JsonGenerator.Feature f); // 合二为一的Configure方法 public JsonFactory configure(JsonFactory.Feature f, boolean state); public JsonFactory configure(JsonParser.Feature f, boolean state); public JsonFactory configure(JsonGenerator.Feature f, boolean state);
使用示例:
@Test public void test3() throws IOException { String jsonStr = "{\"age\":18, \"age\": 28 }"; JsonFactory factory = new JsonFactory(); factory.enable(JsonParser.Feature.STRICT_DUPLICATE_DETECTION); try (JsonParser jsonParser = factory.createParser(jsonStr)) { // 使用factory定制将不生效 // factory.enable(JsonParser.Feature.STRICT_DUPLICATE_DETECTION); while (jsonParser.nextToken() != JsonToken.END_OBJECT) { String fieldname = jsonParser.getCurrentName(); if ("age".equals(fieldname)) { jsonParser.nextToken(); System.out.println(jsonParser.getIntValue()); } } } }