Должен ли я объявить Джексона ObjectMapper как статическое поле? - PullRequest
319 голосов
/ 11 октября 2010

Класс ObjectMapper библиотеки Джексона кажется потокобезопасным .

Означает ли это, что я должен объявить свой ObjectMapper как статическое поле, подобное

* 1008?*

а не как поле уровня экземпляра, как это?

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

Ответы [ 5 ]

464 голосов
/ 12 октября 2010

Да, это безопасно и рекомендуется.

Единственное предостережение со страницы, на которую вы ссылались, это то, что вы не можете изменять конфигурацию маппера, когда он используется совместно; но вы не меняете конфигурацию, так что все в порядке. Если вам нужно изменить конфигурацию, вы сделаете это из статического блока, и это будет хорошо.

РЕДАКТИРОВАТЬ : (2013/10)

С 2.0 и выше, выше можно дополнить, отметив, что есть еще лучший способ: использовать ObjectWriter и ObjectReader объекты, которые можно построить с помощью ObjectMapper. Они являются полностью неизменяемыми, поточно-ориентированными, что означает, что теоретически невозможно вызвать проблемы с безопасностью потоков (которые могут возникнуть при ObjectMapper, если код пытается переконфигурировать экземпляр).

37 голосов
/ 22 марта 2016

Хотя ObjectMapper является потокобезопасным, я бы настоятельно не рекомендовал объявлять его статической переменной, особенно в многопоточных приложениях. Даже не потому, что это плохая практика, а потому, что вы подвергаетесь серьезному риску взаимоблокировки. Я говорю это на собственном опыте. Я создал приложение с 4 одинаковыми потоками, которые получали и обрабатывали данные JSON из веб-сервисов. Мое приложение часто зависало по следующей команде, согласно дампу потока:

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

Кроме того, производительность не была хорошей. Когда я заменил статическую переменную на переменную, основанную на экземпляре, задержка исчезла, а производительность увеличилась в четыре раза. То есть 2,4 миллиона документов JSON были обработаны за 40 минут 56 секунд, вместо 2,5 часов ранее.

2 голосов
/ 24 апреля 2013

Хотя можно объявить статический ObjectMapper с точки зрения безопасности потоков, вы должны знать, что создание статических переменных Object в Java считается плохой практикой. Подробнее см. Почему статические переменные считаются злыми? (и, если хотите, мой ответ )

Короче говоря, статики следует избегать, потому что это затрудняет написание кратких модульных тестов. Например, в случае статического финального ObjectMapper вы не можете заменить сериализацию JSON на фиктивный код или запрет на операции.

Кроме того, статический финал не позволяет вам когда-либо реконфигурировать ObjectMapper во время выполнения. Возможно, вы сейчас не представляете себе причину этого, но если вы заблокируете себя в статическом конечном шаблоне, ничто, кроме разрушения загрузчика классов, не позволит вам повторно инициализировать его.

В случае ObjectMapper это хорошо, но в целом это плохая практика, и нет никакого преимущества в использовании одноэлементного шаблона или инверсии управления для управления вашими долгоживущими объектами.

0 голосов
/ 01 октября 2018

Уловка, которую я извлек из этого PR , если вы не хотите определять ее как статическую конечную переменную, но хотите сэкономить немного накладных расходов и гарантировать безопасность потока.

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

кредит автору.

0 голосов
/ 28 апреля 2017

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)

Метод _hashMapSuperInterfaceChain в классе com.fasterxml.jackson.databind.type.TypeFactory синхронизирован. Увижу раздоры на том же при высоких нагрузках.

Может быть еще одна причина избегать статического ObjectMapper

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...