我应该将Jackson的ObjectMapper声明为静态字段吗?

oipij1gg  于 7个月前  发布在  其他
关注(0)|答案(6)|浏览(115)

Jackson库的ObjectMapperseems to be thread safe
这是否意味着我应该像这样将ObjectMapper声明为静态字段

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

而不是像这样的示例级字段?

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

oo7oh9g91#

是的,这是安全和推荐的。
你提到的页面中唯一的警告是,一旦共享了Map器,你就不能修改它的配置;但是你没有改变配置,所以这很好。如果您确实需要更改配置,您可以从静态块中进行更改,这也很好。

编辑:(2013/10)

在2.0及以上版本中,可以通过注意到有一种更好的方法来增强上述内容:使用ObjectWriterObjectReader对象,它们可以由ObjectMapper构造。它们是完全不可变的,线程安全的,这意味着理论上甚至不可能导致线程安全问题(如果代码试图重新配置示例,ObjectMapper可能会发生)。

hxzsmxv2

hxzsmxv22#

虽然ObjectMapper是线程安全的,但我强烈建议不要将其声明为静态变量,特别是在多线程应用程序中。这并不是因为它是一个糟糕的实践,而是因为您正在冒着死锁的巨大风险。我是根据自己的经验说的。我创建了一个具有4个相同线程的应用程序,这些线程从Web服务中获取和处理JSON数据。根据线程转储,我的应用程序经常在执行以下命令时停止:

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

除此之外,表现并不好。当我用基于示例的变量替换静态变量时,停顿消失了,性能翻了两番。也就是说,240万个JSON文档在40分钟56秒内被处理,而不是之前的2.5小时。

deikduxw

deikduxw3#

如果你不想把它定义为一个静态的final变量,但想保存一点开销并保证线程安全,我从这个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();
}

作者的信用。

zour9fqk

zour9fqk4#

尽管从线程安全性的Angular 来看,声明静态ObjectMapper是安全的,但您应该意识到,在Java中构造静态Object变量被认为是不好的做法。有关详细信息,请参阅Why are static variables considered evil?(如果您愿意,请参阅my answer
简而言之,应该避免静态测试,因为静态测试会使编写简洁的单元测试变得困难。例如,使用静态final ObjectMapper,您不能将JSON序列化换成伪代码或no-op。
此外,静态final防止您在运行时重新配置ObjectMapper。您现在可能无法想象这样做的原因,但是如果您将自己锁定在静态final模式中,那么除了拆除类加载器之外,没有什么可以让您重新初始化它。
在ObjectMapper的情况下,它是好的,但一般来说,这是一个坏的做法,并没有比使用单例模式或控制反转来管理长期对象的优势。

dluptydi

dluptydi5#

  • 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)

com.fasterxml.Jackson.databind.type.TypeFactory中的方法_hashMapSuperInterfaceChain已同步。我看到在高负载下同样存在争用。
这可能是避免使用静态ObjectMapper的另一个原因

fcy6dtqo

fcy6dtqo6#

这个问题可能很老了,但我是这么做的。
ObjectMapper示例保存在线程安全的单例中:

public final class JacksonObjectMapperHolder {

  private static volatile JacksonObjectMapperHolder INSTANCE;

  private static final Object MUTEX = new Object();

  public static JacksonObjectMapperHolder getInstance() {
    JacksonObjectMapperHolder instance = INSTANCE;

    if(instance == null) {
      synchronized(MUTEX) {
        instance = INSTANCE;

        if(instance == null) {
          INSTANCE = instance = new JacksonObjectMapperHolder();
        }
      }
    }

    return instance;
  }

  private final ObjectMapper objectMapper = new ObjectMapper();

  private JacksonObjectMapperHolder() {
    super();
  }

  public final ObjectMapper getObjectMapper() {
    return objectMapper;
  }

}

相关问题