Jackson如何缓存key(在什么时机使用了String.intern()方法)

来源:互联网 发布:域名和ip的区别是什么 编辑:程序博客网 时间:2024/05/27 20:15

两个特性的作用

Jackson在反序列化是有两个可配置的特性:INTERN_FIELD_NAMES和CANONICALIZE_FIELD_NAMES。

 /**         * Feature that determines whether JSON object field names are         * to be canonicalized using {@link String#intern} or not:         * if enabled, all field names will be intern()ed (and caller         * can count on this being true for all such names); if disabled,         * no intern()ing is done. There may still be basic         * canonicalization (that is, same String will be used to represent         * all identical object property names for a single document).         *<p>         * Note: this setting only has effect if         * {@link #CANONICALIZE_FIELD_NAMES} is true -- otherwise no         * canonicalization of any sort is done.         *<p>         * This setting is enabled by default.         */        INTERN_FIELD_NAMES(true),        /**         * Feature that determines whether JSON object field names are         * to be canonicalized (details of how canonicalization is done         * then further specified by         * {@link #INTERN_FIELD_NAMES}).         *<p>         * This setting is enabled by default.         */        CANONICALIZE_FIELD_NAMES(true)

根据注释可以看出来,这两个特性的作用是决定是否要规范化json串的key(即调用key的intern方法),并且只有在CANONICALIZE_FIELD_NAMES生效时,INTERN_FIELD_NAMES才会生效。


那么,这个两个特性是如何起作用的呢?

在获取json串的下一个token时,即ReaderBasedJsonParser的nextToken()方法中,解析了key的名称,代码如下:

boolean inObject = _parsingContext.inObject();        if (inObject) {           // First, field name itself:            String name = _parseName(i);//解析key的名称            _parsingContext.setCurrentName(name);            _currToken = JsonToken.FIELD_NAME;            i = _skipWS();            if (i != INT_COLON) {                _reportUnexpectedChar(i, "was expecting a colon to separate field name and value");            }            i = _skipWS();        }

在跟到_parseName(inti)中,可以发现这个方法调用了_parseName2(intstartPtr, inthash, intendChar),方法_parseName2方法返回的是

_symbols.findSymbol(buf, start, len, hash),看一下findSymbol的实现会先后看到下面两个实现逻辑
逻辑1:
if (!_canonicalize) { // [JACKSON-259]    return new String(buffer, start, len);}
逻辑2:
 String newSymbol = new String(buffer, start, len);        if (_intern) {            newSymbol = InternCache.instance.intern(newSymbol);        }

逻辑1中,如果没有配置CANONICALIZE_FIELD_NAMES,直接返回了key的名字,逻辑2中,如果配置了INTERN_FIELD_NAMES,调用intern方法。

_symbols及两个字段_canonicalize和_intern是怎么初始化的

在ObjectMapper的readValue(String content, Class<T> valueType)方法中,先初始化了jsonParser(在JsonFactory的createParser方法中),
protected JsonParser _createParser(Reader r, IOContext ctxt)        throws IOException, JsonParseException    {        return new ReaderBasedJsonParser(ctxt, _parserFeatures, r, _objectCodec,                _rootCharSymbols.makeChild(isEnabled(JsonFactory.Feature.CANONICALIZE_FIELD_NAMES),                        isEnabled(JsonFactory.Feature.INTERN_FIELD_NAMES)));    }

构造ReaderBasedJsonParser的第三个参数是,完成了_symbols及两个字段的初始化。

InternCache是什么

它实现了ConcurrentHashMap,为的是防止多次调用同一个字符串的intern方法。

0 0