Moet ik Jackson’s ObjectMapper declareren als een statisch veld?

De ObjectMapper-klasse van de Jackson-bibliotheek lijkt thread-safete zijn.

Betekent dit dat ik mijn ObjectMappermoet declareren als een statisch veld zoals dit

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

in plaats van als een veld op instantieniveau zoals dit?

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

Antwoord 1, autoriteit 100%

Ja, dat is veilig en aanbevolen.

Het enige voorbehoud van de pagina waarnaar u verwees, is dat u de configuratie van de mapper niet meer kunt wijzigen als deze eenmaal is gedeeld; maar je verandert de configuratie niet, dus dat is prima. Als je de configuratie zou moeten wijzigen, zou je dat doen vanuit het statische blok en dat zou ook goed zijn.

BEWERKEN: (2013/10)

Met 2.0 en hoger kan bovenstaande worden aangevuld door op te merken dat er een nog betere manier is: gebruik ObjectWriteren ObjectReader-objecten, die kunnen worden geconstrueerd door ObjectMapper.
Ze zijn volledig onveranderlijk, thread-safe, wat betekent dat het theoretisch zelfs niet mogelijk is om thread-veiligheidsproblemen te veroorzaken (wat kan optreden met ObjectMapperals code probeert de instantie opnieuw te configureren).


Antwoord 2, autoriteit 13%

Hoewel ObjectMapper thread-safe is, zou ik het ten zeerste afraden om het als een statische variabele te declareren, vooral in toepassingen met meerdere threads.
Niet eens omdat het een slechte gewoonte is, maar omdat je een groot risico loopt vast te lopen. Ik vertel het uit eigen ervaring. Ik heb een applicatie gemaakt met 4 identieke threads die JSON-gegevens van webservices ontvingen en verwerkten.
Mijn toepassing liep regelmatig vast bij het volgende commando, volgens de threaddump:

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

Bovendien waren de prestaties niet goed.
Toen ik de statische variabele verving door de instantiegebaseerde variabele, verdween de stalling en verviervoudigden de prestaties. D.w.z. 2,4 miljoen JSON-documenten werden verwerkt in 40min.56sec., in plaats van 2,5 uur eerder.


Antwoord 3, autoriteit 2%

Een truc die ik heb geleerd van deze PRals je dat niet wilt definieer het als een statische eindvariabele, maar wil wat overhead besparen en thread-safe garanderen.

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();
}

met dank aan de auteur.


Antwoord 4

Hoewel het veilig is om een ​​statische ObjectMapper te declareren in termen van threadveiligheid, moet u zich ervan bewust zijn dat het construeren van statische objectvariabelen in Java als een slechte gewoonte wordt beschouwd. Voor meer details, zie Waarom worden statische variabelen als slecht beschouwd?(en als je wilt, mijn antwoord)

Kortom, statische gegevens moeten worden vermeden, omdat ze het schrijven van beknopte unit-tests moeilijk maken. Met een statische definitieve ObjectMapper kunt u bijvoorbeeld de JSON-serialisatie niet verwisselen voor dummy-code of een no-op.

Bovendien voorkomt een statische finale dat u ObjectMapper tijdens runtime ooit opnieuw kunt configureren. Je ziet daar nu misschien geen reden voor, maar als je jezelf vastzet in een statisch eindpatroon, kun je door de classloader af te breken deze opnieuw initialiseren.

In het geval van objectsmapper zijn prima, maar in het algemeen is het een slechte praktijk en is er geen voordeel ten opzichte van een singleton-patroon of inversie-van-controle om uw langlevende objecten te beheren.

Other episodes