क्या मुझे जैक्सन के ऑब्जेक्टमैपर को एक स्थिर क्षेत्र के रूप में घोषित करना चाहिए?


361

जैक्सन लाइब्रेरी की ObjectMapperकक्षा थ्रेड सुरक्षित लगती है

क्या इसका मतलब यह है कि मुझे ObjectMapperइस तरह से एक स्थिर क्षेत्र के रूप में घोषित करना चाहिए

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

इस तरह के एक उदाहरण के स्तर के क्षेत्र के बजाय?

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

जवाबों:


505

हां, यह सुरक्षित और अनुशंसित है।

आपके द्वारा निर्दिष्ट पृष्ठ से एकमात्र चेतावनी यह है कि साझा करने के बाद आप मैपर के कॉन्फ़िगरेशन को संशोधित नहीं कर सकते हैं; लेकिन आप कॉन्फ़िगरेशन नहीं बदल रहे हैं, इसलिए यह ठीक है। यदि आपको कॉन्फ़िगरेशन बदलने की आवश्यकता है, तो आप स्टेटिक ब्लॉक से ऐसा करेंगे और यह ठीक भी होगा।

संपादित करें : (2013/10)

2.0 और इसके बाद के संस्करण के साथ, यह देखते हुए संवर्धित किया जा सकता है कि एक और भी बेहतर तरीका है: उपयोग ObjectWriterऔर ObjectReaderऑब्जेक्ट, जिसका निर्माण किया जा सकता है ObjectMapper। वे पूरी तरह से अपरिवर्तनीय, थ्रेड-सेफ़ हैं, जिसका अर्थ है कि थ्रेड-सेफ्टी समस्याएँ पैदा करना भी सैद्धांतिक रूप से संभव नहीं है (जो ObjectMapperकि कोड को फिर से कॉन्फ़िगर करने की कोशिश करने पर कोड के साथ हो सकता है )।


23
@StaxMan: मैं थोड़ा चिंतित हूँ अगर कहा जाता है के ObjectMapperबाद भी थ्रेड-सुरक्षित ObjectMapper#setDateFormat()है। यह ज्ञात है कि SimpleDateFormatथ्रेड सुरक्षित नहीं है , इस प्रकार ObjectMapperयह तब तक नहीं होगा जब तक कि यह SerializationConfigप्रत्येक के पहले क्लोन न हो writeValue()(मुझे संदेह है)। क्या आप मेरे डर को मिटा सकते हैं?
dma_k

49
DateFormatवास्तव में हुड के नीचे क्लोन किया गया है। वहां अच्छा संदेह है, लेकिन आप कवर किए गए हैं। :)
StaxMan

3
मैंने एक बड़े उद्यम एप्लिकेशन की इकाई / एकीकरण परीक्षणों के दौरान अजीब व्यवहार का सामना किया है। जब ObjectMapper को स्थिर अंतिम श्रेणी विशेषता के रूप में रखा जाता है तो मैंने PermGen मुद्दों का सामना करना शुरू कर दिया। क्या कोई संभावित कारणों की व्याख्या करने के लिए परवाह करेगा? मैं जैकसन-डेटाबाइंड संस्करण 2.4.1 का उपयोग कर रहा था।
अलेजो सेबलोस

2
@MiklosKrivan क्या आपने बिल्कुल देखा है ObjectMapper?! विधियों का नाम writer()और reader()(और कुछ readerFor(), writerFor()) हैं।
StaxMan

2
कोई mapper.with()कॉल नहीं है (जैक्सन में "के साथ" का तात्पर्य एक नए उदाहरण के निर्माण से है, और धागा-सुरक्षित निष्पादन)। लेकिन विन्यास में परिवर्तन के बारे में: कोई जाँच नहीं की जाती है, इसलिए विन्यास तक ObjectMapperपहरा होना चाहिए। जैसा कि "कॉपी ()": हाँ, यह एक नई नई प्रति बनाता है जो पूरी तरह से (पुनः) कॉन्फ़िगर हो सकती है, समान नियमों के अनुसार: इसे पहले कॉन्फ़िगर करें, फिर उपयोग करें, और यह ठीक है। गैर-तुच्छ लागत जुड़ी हुई है (क्योंकि प्रतिलिपि किसी भी कैश किए गए हैंडलर का उपयोग नहीं कर सकती है), लेकिन यह सुरक्षित तरीका है, हां।
StaxMan

53

यद्यपि ObjectMapper थ्रेड सुरक्षित है, मैं इसे एक स्थिर चर के रूप में घोषित करने से दृढ़ता से हतोत्साहित करूंगा, विशेष रूप से मल्टीथ्रेडेड एप्लिकेशन में। इसलिए भी नहीं कि यह एक बुरा अभ्यास है, बल्कि इसलिए कि आप गतिरोध का भारी जोखिम उठा रहे हैं। मैं इसे अपने अनुभव से कह रहा हूं। मैंने 4 समान थ्रेड्स के साथ एक एप्लिकेशन बनाया जो वेब सेवाओं से JSON डेटा प्राप्त कर रहे थे और प्रसंस्करण कर रहे थे। मेरा आवेदन अक्सर थ्रेड डंप के अनुसार, निम्न कमांड पर रोक रहा था:

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

इसके अलावा, प्रदर्शन अच्छा नहीं था। जब मैंने स्थैतिक चर को उदाहरण आधारित चर के साथ बदल दिया, तो स्टालिंग गायब हो गया और प्रदर्शन चौपट हो गया। Ie 2.4 लाखों JSON दस्तावेज़ों को पहले 2.5 घंटे के बजाय 40min.56sec में संसाधित किया गया था।


15
गैरी का जवाब पूरी तरह से समझ में आता है। लेकिन ObjectMapperहर वर्ग के उदाहरण के लिए एक उदाहरण के साथ जाने से ताले को रोका जा सकता है, लेकिन बाद में जीसी पर वास्तव में भारी पड़ सकता है (कल्पना करें कि आपके द्वारा बनाए गए वर्ग के प्रत्येक उदाहरण के लिए एक ऑब्जेक्टमैपर उदाहरण)। एक मध्य पथ दृष्टिकोण, ObjectMapperआवेदन में केवल एक (सार्वजनिक) स्थिर उदाहरण रखने के बजाय , आप हर वर्ग में एक (निजी) स्थिर उदाहरण घोषित कर सकते हैं । यह एक वैश्विक लॉक (लोड क्लास-वार वितरित करके) को कम करेगा, और कोई भी नई वस्तु भी नहीं बनाएगा, इसलिए जीसी पर भी प्रकाश डालें। ObjectMapper
अभिमन्यु

और निश्चित रूप से, एक बनाए रखना ObjectPool सबसे अच्छा तरीका है जिसके साथ आप जा सकते हैं - जिससे सबसे अच्छा GCऔर Lockप्रदर्शन होगा। आप अपाचे-आम के ObjectPoolकार्यान्वयन के लिए निम्नलिखित लिंक का उल्लेख कर सकते हैं । commons.apache.org/proper/commons-pool/api-1.6/org/apache/…
Abhidemon

16
मैं एक विकल्प सुझाऊंगा: ObjectMapperकहीं न कहीं स्थिर रहें , लेकिन केवल ObjectReader/ ObjectWriterउदाहरणों (सहायक विधियों के माध्यम से) प्राप्त करें, अन्य स्थानों (या गतिशील रूप से कॉल) के संदर्भों को बनाए रखें। ये पाठक / लेखक ऑब्जेक्ट न केवल पूरी तरह से थ्रेड-सुरक्षित wrt रिफ़िगरेशन हैं, बल्कि बहुत हल्के वजन (wrt मैपर इंस्टेंस) भी हैं। इसलिए हजारों संदर्भों को रखने से स्मृति का अधिक उपयोग नहीं होता है।
स्टेक्समैन

तो ObjectReader उदाहरणों को कॉल करने के लिए अवरुद्ध नहीं कर रहे हैं कहते हैं कि objectReader.readTree को multithreaded एप्लिकेशन में कहा जाता है, थ्रेड को किसी अन्य थ्रेड पर प्रतीक्षा में अवरुद्ध नहीं किया जाएगा, जैकसन 2.8.x का उपयोग करके
Xephonia

1

यद्यपि थ्रेड सुरक्षा के संदर्भ में एक स्थिर ObjectMapper घोषित करना सुरक्षित है, आपको पता होना चाहिए कि जावा में स्थिर ऑब्जेक्ट चर का निर्माण करना बुरा अभ्यास माना जाता है। अधिक जानकारी के लिए, देखें कि स्थिर चर को बुराई क्यों माना जाता है? (और यदि आप चाहें, तो मेरा जवाब )

संक्षेप में, स्टेटिक्स से बचना चाहिए क्योंकि संक्षिप्त इकाई परीक्षणों को लिखना मुश्किल हो जाता है। उदाहरण के लिए, एक स्थिर अंतिम ObjectMapper के साथ, आप डमी कोड या नो-ऑप के लिए JSON क्रमांकन को स्वैप नहीं कर सकते।

इसके अलावा, एक स्थैतिक फाइनल आपको रनटाइम पर कभी भी ObjectMapper को पुन: कॉन्फ़िगर करने से रोकता है। अब आप इसके लिए कोई कारण नहीं बता सकते हैं, लेकिन यदि आप अपने आप को एक स्थिर अंतिम पैटर्न में बंद कर देते हैं, तो क्लास लोडर को फाड़ने के लिए कुछ भी कम नहीं होने देता है।

ObjectMapper के मामले में यह ठीक है, लेकिन सामान्य तौर पर यह बुरा व्यवहार है और आपके लंबे समय तक जीवित वस्तुओं का प्रबंधन करने के लिए एक सिंगलटन पैटर्न या व्युत्क्रम नियंत्रण का उपयोग करने पर कोई फायदा नहीं है।


27
मैं यह सुझाव दूंगा कि यद्यपि स्थिर स्टेट सिंग्लटन आमतौर पर एक खतरे का संकेत हैं, वहाँ पर्याप्त कारण हैं कि इस मामले में एकल (या, छोटी संख्या) उदाहरण साझा करना समझ में आता है। एक उस के लिए निर्भरता इंजेक्शन का उपयोग करना चाहते हो सकता है; लेकिन एक ही समय में यह पूछने योग्य है कि क्या हल करने के लिए वास्तविक या संभावित समस्या है। यह विशेष रूप से परीक्षण पर लागू होता है: सिर्फ इसलिए कि कुछ समस्या हो सकती है कुछ मामले में इसका मतलब यह नहीं है कि यह आपके उपयोग के लिए है। तो: समस्याओं के बारे में पता होना, महान। "एक आकार सभी फिट बैठता है", इतना अच्छा नहीं मानते।
StaxMan

3
स्पष्ट रूप से किसी भी डिजाइन निर्णय के साथ जुड़े मुद्दों को समझना महत्वपूर्ण है, और यदि आप अपने उपयोग के मामले में समस्याओं के कारण के बिना कुछ कर सकते हैं तो परिभाषा के अनुसार आप किसी भी समस्या का कारण नहीं बनेंगे। हालाँकि, मैं तर्क दूंगा कि स्थैतिक उदाहरणों के उपयोग से कोई लाभ नहीं है और यह भविष्य में महत्वपूर्ण मुसीबत का द्वार खोलता है क्योंकि आपका कोड विकसित होता है या अन्य डेवलपर्स को सौंप दिया जाता है जो आपके डिज़ाइन निर्णयों को नहीं समझ सकते हैं। यदि आपका ढांचा विकल्पों का समर्थन करता है, तो स्थिर कारणों से बचने का कोई कारण नहीं है, निश्चित रूप से उनके लिए कोई लाभ नहीं हैं।
JBCP

11
मुझे लगता है कि यह चर्चा बहुत सामान्य और कम उपयोगी स्पर्शरेखा में चली गई। मुझे यह सुझाव देने में कोई समस्या नहीं है कि स्थैतिक एकल के संदिग्ध होने के लिए अच्छा है। मैं अभी इस विशेष मामले के उपयोग के लिए बहुत परिचित हूं और मुझे नहीं लगता कि सामान्य दिशानिर्देशों के सेट से कोई विशिष्ट निष्कर्ष तक पहुंच सकता है। तो मैं इसे उस पर छोड़ दूंगा।
StaxMan

1
देर से टिप्पणी, लेकिन ObjectMapper विशेष रूप से इस धारणा से असहमत नहीं होगा? यह उजागर करता है readerForऔर writerForजो मांग पर पैदा करता है ObjectReaderऔर ObjectWriterउदाहरण देता है। तो मैं कहूंगा कि मैपर को आरंभिक कॉन्फिगरेशन के साथ कहीं स्थिर रखें, फिर रीडर्स / राइटर्स को प्रति केस कॉन्फिग के साथ मिला दें क्योंकि आपको उनकी आवश्यकता है?
कैरिघन

1

एक ट्रिक मैंने इस 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();
}

लेखक को श्रेय।


2
लेकिन एक मेमोरी लीक होने का खतरा है क्योंकि ObjectMapperवसीयत उस धागे से जुड़ी होगी जो एक पूल का हिस्सा हो सकता है।
केनस्टन चोई

@KenstonChoi एक समस्या नहीं होनी चाहिए, AFAIU। धागे आते हैं और जाते हैं, धागा स्थानीय लोग आते हैं और धागे के साथ जाते हैं। एक साथ थ्रेड्स की मात्रा के आधार पर आप मेमोरी को खर्च कर सकते हैं या नहीं कर सकते हैं, लेकिन मुझे "लीक" नहीं दिख रहा है।
इवान बालाशोव

2
@ इवानबालाशोव, लेकिन अगर धागा बनाया जाता है / एक थ्रेड पूल से / से लौटाया जाता है (जैसे, टॉमकैट जैसे कंटेनर), यह रहता है। यह कुछ मामलों में वांछित हो सकता है, लेकिन कुछ के बारे में हमें जागरूक होना चाहिए।
केनस्टन चोई

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

विधि _hashMapSuperInterfaceChain in com .fasterxml.jackson.databind.type.TypeFactory सिंक्रनाइज़ किया गया है। उच्च भार पर उसी पर विवाद देख रहा हूँ।

एक स्थिर ObjectMapper से बचने का एक और कारण हो सकता है


1
नवीनतम संस्करणों की जांच करना सुनिश्चित करें (और शायद आपके द्वारा उपयोग किए जाने वाले संस्करण को इंगित करें)। रिपोर्ट किए गए मुद्दों के आधार पर लॉकिंग में सुधार किया गया है, और प्रकार रिज़ॉल्यूशन (f.ex) को जैक्सन 2.7 के लिए पूरी तरह से फिर से लिखा गया है। हालांकि इस मामले में, TypeReferenceउपयोग करने के लिए थोड़ा महंगा चीज है: यदि संभव हो तो, इसे हल करने JavaTypeसे काफी प्रसंस्करण से बचा TypeReferenceजा सकता है ( एस नहीं हो सकता है - दुर्भाग्य से - कारणों के लिए कैश किया गया है कि मैं यहां खुदाई नहीं करूंगा), क्योंकि वे "पूरी तरह से हल" (सुपर-टाइप, जेनेरिक टाइपिंग आदि) हैं।
स्टेक्समैन
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.