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

两个特性的作用

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).
         *

* Note: this setting only has effect if * {@link #CANONICALIZE_FIELD_NAMES} is true -- otherwise no * canonicalization of any sort is done. *

* 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}). *

* 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( int i )中,可以发现这个方法调用了 _parseName2( int startPtr, int hash, int endChar), 方法_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方法。

 
  

你可能感兴趣的:(Jackson如何缓存key(在什么时机使用了String.intern()方法))