2010-10-11 8 views

Répondre

346

Oui, c'est sûr et recommandé. Le seul inconvénient de la page que vous avez mentionnée est que vous ne pouvez pas modifier la configuration du mappeur une fois qu'il est partagé; mais vous ne changez pas la configuration, donc c'est bien. Si vous aviez besoin de changer de configuration, vous le feriez à partir du bloc statique et tout irait bien aussi.

EDIT: (2013/10)

Avec 2,0 et au-dessus, ci-dessus peut être augmentée en notant qu'il y a une meilleure façon: utiliser ObjectWriter et ObjectReader objets, qui peut être construit par ObjectMapper. Ils sont entièrement immuables, thread-safe, ce qui signifie qu'il n'est même pas théoriquement possible de provoquer des problèmes de sécurité des threads (ce qui peut se produire avec ObjectMapper si le code essaie de reconfigurer l'instance).

+0

Avez-vous une source de référence? –

+51

Opps. Je réalise que tu es le développeur de Jackson. Merci pour le super logiciel! Je le compare à JSONObject et à gjson, et j'ai trouvé Jackson répondre à mes besoins. –

+8

Hey pas de problème - heureux d'entendre cela – StaxMan

3

Bien qu'il soit sûr de déclarer un ObjectMapper statique en termes de sécurité des threads, sachez que la construction de variables Object statiques en Java est considérée comme une mauvaise pratique. Pour plus de détails, voir Why are static variables considered evil? (et si vous le souhaitez, my answer)

En résumé, la statique doit être évitée car il est difficile d'écrire des tests unitaires concis. Par exemple, avec un ObjectMapper final statique, vous ne pouvez pas échanger la sérialisation JSON pour un code factice ou un no-op. En outre, une finale statique vous empêche de reconfigurer ObjectMapper au moment de l'exécution. Vous ne pensez peut-être pas à une raison pour cela maintenant, mais si vous vous enfermez dans un schéma final statique, rien de moins que de démolir le chargeur de classe vous permettra de le réinitialiser. Dans le cas de ObjectMapper c'est bon, mais en général c'est une mauvaise pratique et il n'y a aucun avantage à utiliser un pattern singleton ou une inversion de contrôle pour gérer vos objets de longue durée.

+18

Je suggère que, bien que les singletons STATEFUL statiques soient typiquement un signe de danger, il y a suffisamment de raisons pour lesquelles, dans ce cas, le partage d'un seul (ou, petit nombre) d'instances est logique. On peut vouloir utiliser l'injection de dépendance pour cela; mais en même temps, il vaut la peine de se demander s'il y a un problème réel ou potentiel à résoudre. Cela s'applique particulièrement aux tests: le simple fait que quelque chose soit problématique dans certains cas ne signifie pas que c'est pour votre usage. Donc: être conscient des problèmes, super. En supposant "taille unique", pas si bon. – StaxMan

+3

Il est évidemment important de comprendre les problèmes liés à toute décision de conception, et si vous pouvez faire quelque chose sans causer de problèmes dans votre cas d'utilisation, vous ne poserez aucun problème par définition. Cependant, je dirais qu'il n'y a aucun avantage à l'utilisation d'instances statiques et cela ouvre la porte à des problèmes importants à l'avenir lorsque votre code évolue ou est transmis à d'autres développeurs qui pourraient ne pas comprendre vos décisions de conception. Si votre framework supporte des alternatives, il n'y a aucune raison de ne pas éviter les instances statiques, il n'y a certainement aucun avantage à les utiliser. – JBCP

+7

Je pense que cette discussion va dans des tangentes très générales et moins utiles. Je n'ai aucun problème à suggérer qu'il est bon de se méfier des singletons statiques. Je viens d'être très familier avec l'utilisation de ce cas particulier et je ne pense pas que l'on puisse arriver à des conclusions spécifiques à partir d'un ensemble de directives générales. Je vais donc en rester là. – StaxMan

22

Même si ObjectMapper est thread-safe, je déconseille fortement de le déclarer comme une variable statique, en particulier dans les applications multithread. Pas même parce que c'est une mauvaise pratique, mais parce que vous courez un risque important de blocage. Je le dis de ma propre expérience. J'ai créé une application avec 4 threads identiques qui recevaient et traitaient des données JSON à partir de services web. Ma demande stagnait souvent sur la commande suivante, d'après le vidage de fil:

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

A côté de cela, la performance n'a pas été bonne. Lorsque j'ai remplacé la variable statique par la variable basée sur l'instance, le blocage 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.

+8

La réponse de Gary est tout à fait logique. Mais aller avec une création d'une instance 'ObjectMapper' pour chaque instance de classe peut empêcher les verrous mais peut être très lourd sur le GC plus tard (imaginez une instance ObjectMapper pour chaque instance de la classe que vous créez). Une approche de chemin moyen peut être, au lieu de garder une seule instance 'publicMapper' statique (publique) à travers l'application, vous pouvez déclarer une instance (privée) ** statique ** de' ObjectMapper' ** dans chaque classe **. Cela réduira un verrou global (en répartissant la charge par classe), et ne créera pas non plus de nouvel objet, d'où la lumière sur le GC également. – Abhidemon

+0

Et bien sûr, maintenir un 'ObjectPool' est la meilleure façon de faire, donnant ainsi les meilleures performances' GC' et 'Lock'. Vous pouvez vous référer au lien suivant pour l'implémentation 'ObjectPool' d'apache-common. https://commons.apache.org/proper/commons-pool/api-1.6/org/apache/commons/pool/impl/GenericObjectPool.html – Abhidemon

+5

Je suggérerais une alternative: gardez le 'ObjectMapper' statique quelque part, mais seulement obtenir des instances 'ObjectReader' /' ObjectWriter' (via des méthodes d'assistance), conserver des références à celles d'autres endroits (ou appeler dynamiquement). Ces objets lecteur/graveur ne sont pas seulement entièrement reconfigurables pour les threads, mais aussi très légers (instances wrt mapper). Garder des milliers de références n'ajoute pas beaucoup d'utilisation de la mémoire. – StaxMan

-1

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) 

Procédé _hashMapSuperInterfaceChain dans la classe com.fasterxml.jackson.databind.type.TypeFactory est synchronisé. Voyons la contention sur le même à des charges élevées.

Peut être une autre raison pour éviter un ObjectMapper statique

+0

Assurez-vous de vérifier les dernières versions (et peut-être indiquer la version que vous utilisez ici). Des améliorations ont été apportées au verrouillage en fonction des problèmes rapportés, et la résolution de type (f.ex) a été entièrement réécrite pour Jackson 2.7. Bien que dans ce cas, 'TypeReference' soit peu coûteux à utiliser: si possible, le résoudre en' JavaType' éviterait pas mal de traitement ('TypeReference's ne peut malheureusement pas être mis en cache pour des raisons Je ne vais pas creuser ici), puisqu'ils sont "complètement résolus" (super-type, typage générique etc). – StaxMan

Questions connexes