Dois-je déclarer L'ObjectMapper de Jackson comme un champ statique?

Le Jackson de la bibliothèque ObjectMapper classe semble être thread-safe .

signifie-t-il que je devrais déclarer mon ObjectMapper comme un champ statique comme celui-ci

class Me {
    private static final ObjectMapper mapper = new ObjectMapper();
}

au lieu d'un champ de niveau d'instance comme celui-ci?

class Me {
    private final ObjectMapper mapper = new ObjectMapper();
}
270
demandé sur seh 2010-10-11 20:08:13

5 réponses

Oui, c'est sûr et recommandé.

la seule mise en garde de la page que vous avez mentionnée est que vous ne pouvez pas modifier la configuration du mapper une fois qu'il est partagé; mais vous ne modifiez pas la configuration donc c'est très bien. Si vous aviez besoin de changer la configuration, vous le feriez à partir du bloc statique et ce serait très bien aussi.

MODIFIER : (2013/10)

Avec 2.0 et au-dessus, ci-dessus peuvent être augmentez en notant qu'il y a une façon encore meilleure: utilisez ObjectWriter et ObjectReader objets, qui peuvent être construits par ObjectMapper . Ils sont entièrement immuables, thread-safe, ce qui signifie qu'il n'est même pas théoriquement possible de causer des problèmes de thread-safety (ce qui peut se produire avec ObjectMapper si le code essaie de re-configurer l'instance).

402
répondu StaxMan 2017-06-14 15:36:25

bien que ObjectMapper soit sûr, je déconseille fortement de le déclarer comme une variable statique, en particulier dans l'application multithread. Même pas parce que c'est une mauvaise pratique, mais parce que vous utilisez un lourd risque d'interblocage. Je vais dire à partir de ma propre expérience. J'ai créé une application avec 4 threads identiques qui obtenaient et traitaient des données JSON des services web. Mon application était souvent bloquée sur la commande suivante, selon le thread dump:

Map aPage = mapper.readValue(reader, Map.class);

de plus, la performance n'était pas bonne. Quand j'ai remplacé la variable statique par la variable basée sur l'instance, le décrochage a disparu et les performances ont quadruplé. C'est-à-dire: 2,4 millions de documents JSON ont été traités en 40min.56sec., au lieu de 2,5 heures auparavant.

27
répondu Gary Greenberg 2016-03-22 18:36:05

bien qu'il soit sûr de déclarer un ObjectMapper statique en termes de sécurité de thread, vous devez être conscient que la construction de variables d'objet statique en Java est considérée comme une mauvaise pratique. Pour plus de détails, voir pourquoi les variables statiques sont-elles considérées comme mauvaises? (et si vous voulez, ma réponse )

en bref, la statique doit être évitée parce qu'elle rend difficile la rédaction de tests unitaires concis. Par exemple, avec une finale statique ObjectMapper, vous ne pouvez pas échanger la sérialisation JSON contre un code fictif ou un no-op.

de plus, une finale statique vous empêche de reconfigurer ObjectMapper à l'exécution. Vous ne pouvez peut-être pas imaginer une raison pour cela maintenant, mais si vous vous enfermez dans un schéma final statique, rien de moins de démolir le classloader vous permettra de le ré-initialiser.

dans le cas D'ObjectMapper son amende, mais en général, il est de mauvaise pratique et il n'y a pas avantage par rapport à l'utilisation d'un modèle unique ou d'une inversion de contrôle pour gérer vos objets à longue durée de vie.

2
répondu JBCP 2017-05-23 10:31:12

un truc que j'ai appris de ce PR si vous ne voulez pas le Définir comme une variable finale statique, mais que vous voulez sauver un peu de overhead et garantir la sécurité du thread.

private static final ThreadLocal<ObjectMapper> om = new ThreadLocal<ObjectMapper>() {
    @Override
    protected ObjectMapper initialValue() {
        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        return objectMapper;
    }
};

public static ObjectMapper getObjectMapper() {
    return om.get();
}

crédit à l'auteur.

0
répondu Adam Lin 2018-10-01 05:19:29

com.fasterxml.Jackson.databind.type.TypeFactory._hashMapSuperInterfaceChain (HierarchicType)

com.fasterxml.jackson.databind.type.TypeFactory._findSuperInterfaceChain(Type, Class)
  com.fasterxml.jackson.databind.type.TypeFactory._findSuperTypeChain(Class, Class)
     com.fasterxml.jackson.databind.type.TypeFactory.findTypeParameters(Class, Class, TypeBindings)
        com.fasterxml.jackson.databind.type.TypeFactory.findTypeParameters(JavaType, Class)
           com.fasterxml.jackson.databind.type.TypeFactory._fromParamType(ParameterizedType, TypeBindings)
              com.fasterxml.jackson.databind.type.TypeFactory._constructType(Type, TypeBindings)
                 com.fasterxml.jackson.databind.type.TypeFactory.constructType(TypeReference)
                    com.fasterxml.jackson.databind.ObjectMapper.convertValue(Object, TypeReference)

la méthode hashmapsuper interfacechain dans la classe com.fasterxml.Jackson.databind.type.La TypeFactory est synchronisée. Je vois des disputes sur la même chose à des charges élevées.

Peut être une autre raison d'éviter une statique ObjectMapper

-1
répondu Harshit 2017-04-28 10:16:08