题
杰克逊图书馆的 ObjectMapper
班级 似乎是安全的.
这是否意味着我应该宣布我的 ObjectMapper
作为这样的静态领域
class Me {
private static final ObjectMapper mapper = new ObjectMapper();
}
而不是像这样的实例级字段?
class Me {
private final ObjectMapper mapper = new ObjectMapper();
}
解决方案
是的,这是安全的建议。
您引用的页面中唯一的警告是,一旦共享映射器,就无法修改对映射器的配置;但是您没有更改配置,所以很好。如果您确实需要更改配置,则可以从静态块中执行此操作,也可以。
编辑: (2013/10)
使用2.0及以上,可以通过指出有更好的方法来增强上述:使用 ObjectWriter
和 ObjectReader
对象,可以由 ObjectMapper
。它们是完全不可变的,螺纹安全的,这意味着在理论上甚至都不可能引起线程安全问题(这可能会发生 ObjectMapper
如果代码试图重新配置实例)。
其他提示
尽管ObjectMapper是线程安全的,但我强烈建议将其声明为静态变量,尤其是在多线程应用程序中。甚至不是因为这是一种不好的做法,而是因为您承受着僵局的严重风险。我是根据自己的经验告诉它。我创建了一个使用4个相同线程的应用程序,这些线程正在从Web服务中获取和处理JSON数据。根据线程转储,我的应用程序经常停滞在以下命令上:
Map aPage = mapper.readValue(reader, Map.class);
除此之外,性能不好。当我用基于实例的变量替换静态变量时,失速消失了,性能四倍。 IE在40分钟内处理了2400万个JSON文档,而不是前2.5小时。
尽管可以从线程安全性方面宣布静态对象贴,但您应该意识到,在Java中构建静态对象变量被认为是不良实践。有关更多详细信息,请参阅 为什么静态变量被认为是邪恶的? (如果您愿意, 我的答案)
简而言之,应该避免使用静态,因为很难编写简洁的单位测试。例如,使用静态的最终对象拍摄器,您无法将JSON序列化换成虚拟代码或NO-OP。
此外,静态决赛可防止您在运行时重新配置ObjectMapper。您现在可能不会设想出这样的原因,但是如果您将自己锁定在静态的最终模式中,那么拆除classloader就可以让您重新定位它。
对于ObjectMapper的情况,它的良好,但总的来说,这是不良的实践,使用单例模式或控制倒置来管理您的长寿命对象没有任何优势。
我从中学到的一个把戏 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();
}
归功于作者。
com.fasterxml.jackson.databind.type.typefactory._hashmapsuperinterfacechain(eshierarchictype)
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 已同步。在高载荷下看到同一的争论。
可能是避免静态对象拍摄器的另一个原因