संदर्भ और marshallers लागत बनाने JAXB


120

सवाल थोड़ा सैद्धांतिक है, JAXB संदर्भ, मार्शेलर और अनमरशैलर बनाने की लागत क्या है?

मैंने पाया है कि मेरे कोड को एक ही JAXB संदर्भ रखने से लाभ हो सकता है और संभवतः प्रत्येक मार्शलों पर संदर्भ और मार्शेलर बनाने के बजाय सभी मार्शलों के संचालन के लिए एक ही मार्शलर।

तो JAXB संदर्भ और मार्शेलर / अनमरशैलर बनाने की लागत क्या है? क्या प्रत्येक मार्शलिंग ऑपरेशन के लिए संदर्भ + मार्शेलर बनाना ठीक है या इससे बचना बेहतर है?

जवाबों:


244

नोट: मैं एक्लिप्सलिंक JAXB (MOXy) लीड और JAXB 2 ( JSR-222 ) विशेषज्ञ समूह का सदस्य हूं

JAXBContextधागा सुरक्षित है और इसे केवल एक बार बनाया जाना चाहिए और कई बार मेटाडेटा को इनिशियलाइज़ करने की लागत से बचना चाहिए। Marshallerऔर Unmarshallerथ्रेड सुरक्षित नहीं हैं, लेकिन बनाने के लिए हल्के हैं और प्रति ऑपरेशन बनाया जा सकता है।


7
बहुत बढ़िया जवाब। JAXB पर लीड के रूप में आपके अनुभव के आधार पर अब मैं आश्वस्त हो सकता हूं।
व्लादिमीर

7
मुझे आप पर भरोसा है, लेकिन क्या यह कहीं प्रलेखन में पाया जाना है?
हुरडा

3
यह RI के लिए प्रलेखित है: jaxb.java.net/guide/Performance_and_thread_safety.html (लेकिन Moxy AFAIK नहीं)
Caoilte

39
कृपया इसे जवादोक में निर्दिष्ट करें। इन महत्वपूर्ण पहलुओं को अनिर्दिष्ट किया जाना संतोषजनक नहीं है।
थॉमस डब्ल्यू

6
यह Javadoc में उल्लेख नहीं किया गया है कि JAXBContext थ्रेड सुरक्षित है। और JAXB का उपयोग कैसे करें के हर उदाहरण के बारे में, यह उल्लेख करने में विफल रहता है कि इसे एक बार बनाया जाना चाहिए और थ्रेड्स में साझा किया जाना चाहिए। एक परिणाम के रूप में मैं अब एक और हॉलिंग संसाधन रिसाव को लाइव सिस्टम से हटा रहा हूं। Grrrrrrr।
रेग व्हिटन

42

आदर्श रूप में, आप एक सिंगलटन होना चाहिए JAXBContextऔर स्थानीय उदाहरणों Marshallerऔर Unmarshaller

JAXBContextउदाहरण थ्रेड-सुरक्षित होते हैं Marshallerऔर Unmarshallerइंस्टेंस थ्रेड-सुरक्षित नहीं होते हैं और इन्हें कभी भी थ्रेड में साझा नहीं किया जाना चाहिए।


जवाब के लिए धन्यवाद। दुर्भाग्य से मुझे केवल एक उत्तर का चयन करना है :-)
व्लादिमीर

15

अफ़सोस की बात है कि यह विशेष रूप से javadoc में वर्णित नहीं है। जो मैं बता सकता हूं कि स्प्रिंग एक वैश्विक JAXBContext का उपयोग करता है, जिसे थ्रेड्स के बीच साझा किया जाता है, जबकि यह प्रत्येक मार्शेलिंग ऑपरेशन के लिए एक नया मार्शेलर बनाता है, जिसमें कोड में एक javadoc टिप्पणी के साथ कहा गया है कि JAXB मार्सर्स आवश्यक रूप से थ्रेड-सुरक्षित नहीं हैं।

इस पृष्ठ पर ऐसा ही कहा गया है: https://javaee.github.io/jaxb-v2/doc/user-guide/ch03.html#other-misc विविध-topics-performance- and- thread-safety

मुझे लगता है कि JAXBContext बनाना एक महंगा ऑपरेशन है, क्योंकि इसमें एनोटेशन के लिए स्कैनिंग क्लास और पैकेज शामिल हैं। लेकिन इसे जानना सबसे अच्छा तरीका है।


हाय @JB, विशेष रूप से मापने पर आपकी टिप्पणी और JAXBContext क्यों महँगा जवाब है।
व्लादिमीर

1
जीवन चक्र के महत्वपूर्ण तथ्यों पर जावादोक हमेशा कमजोर रहा है । यह निश्चित रूप से हमें संपत्ति पाने वालों और बसने वालों का तुच्छ दोहराव देता है, लेकिन यह जानने के लिए कि कैसे / जहां एक उदाहरण, उत्परिवर्तन और धागा-सुरक्षा प्राप्त करना या बनाना है .. यह उन सबसे महत्वपूर्ण कारकों को पूरी तरह से याद करने के लिए लगता है। आह :)
थॉमस डब्ल्यू

4

JAXB 2.2 ( JSR-222 ) के लिए यह कहना है, "4.2 JAXBContext" अनुभाग में।

एक JAXBContextउदाहरण बनाने में शामिल ओवरहेड से बचने के लिए, JAXBontext इंस्टेंस का पुनः उपयोग करने के लिए JAXB एप्लिकेशन को प्रोत्साहित किया जाता है । अमूर्त वर्ग JAXBContext के कार्यान्वयन के लिए थ्रेड-सुरक्षित होना आवश्यक है , इस प्रकार, एक आवेदन में कई धागे एक ही JAXBContext उदाहरण साझा कर सकते हैं।

[..]

JAXBContext क्लास को अपरिवर्तनीय और इस प्रकार थ्रेडसेफ़ के लिए डिज़ाइन किया गया है। गतिशील प्रसंस्करण की मात्रा को देखते हुए जो संभवतः JAXBContxt का एक नया उदाहरण बनाते समय हो सकता है, यह अनुशंसा की जाती है कि JAXBContext उदाहरण को थ्रेड्स में साझा किया जाए और अनुप्रयोग प्रदर्शन को बेहतर बनाने के लिए यथासंभव उपयोग किया जाए।

दुर्भाग्य से, विनिर्देश थ्रेड की सुरक्षा के बारे में कोई दावा नहीं करता है Unmarshallerऔर Marshaller। इसलिए यह मानना ​​सबसे अच्छा है कि वे नहीं हैं।


3

मैंने इस समस्या को हल कर लिया है:

  • साझा धागा सुरक्षित JAXBContext और धागा स्थानीय संयुक्त राष्ट्र / मार्शल
  • (इसलिए सैद्धांतिक रूप से, वहाँ के रूप में कई संयुक्त राष्ट्र / मार्शल उदाहरण होंगे जहां धागे हैं जो उन तक पहुंचते हैं)
  • केवल संयुक्त राष्ट्र / मार्शेलर के आरंभीकरण पर तुल्यकालन के साथ ।
public class MyClassConstructor {
    private final ThreadLocal<Unmarshaller> unmarshallerThreadLocal = new ThreadLocal<Unmarshaller>() {
        protected synchronized Unmarshaller initialValue() {
            try {
                return jaxbContext.createUnmarshaller();
            } catch (JAXBException e) {
                throw new IllegalStateException("Unable to create unmarshaller");
            }
        }
    };
    private final ThreadLocal<Marshaller> marshallerThreadLocal = new ThreadLocal<Marshaller>() {
        protected synchronized Marshaller initialValue() {
            try {
                return jaxbContext.createMarshaller();
            } catch (JAXBException e) {
                throw new IllegalStateException("Unable to create marshaller");
            }
        }
    };

    private final JAXBContext jaxbContext;

    private MyClassConstructor(){
        try {
            jaxbContext = JAXBContext.newInstance(Entity.class);
        } catch (JAXBException e) {
            throw new IllegalStateException("Unable to initialize");
        }
    }
}

8
थ्रेडलोक बिना लाभ के, अन्य सूक्ष्म समस्याओं को पेश करेगा। बस एक ही JAXBContext (जो महंगा हिस्सा है) रखें और जब भी आवश्यकता हो एक नया Unmarshaller बनाएं।
यमजोरोस

2

और भी बेहतर!! उपरोक्त पोस्ट से अच्छे समाधान के आधार पर , कंस्ट्रक्टर में सिर्फ एक बार संदर्भ बनाएं , और इसे कक्षा के बजाय सहेजें।

लाइन बदलें:

  private Class clazz;

इसके साथ:

  private JAXBContext jc;

और इस एक के साथ मुख्य निर्माता:

  private Jaxb(Class clazz)
  {
     this.jc = JAXBContext.newInstance(clazz);
  }

तो getMarshaller / getUnmarshaller में आप इस लाइन को हटा सकते हैं:

  JAXBContext jc = JAXBContext.newInstance(clazz);

यह सुधार, मेरे मामले में, प्रसंस्करण समय 60 ~ 70ms से घटकर केवल 5 ~ 10ms हो जाता है


कितना बड़ा xml फ़ाइल था जिसे आप पार्स कर रहे थे। क्या आप बहुत बड़ी xml फ़ाइलों के साथ महत्वपूर्ण सुधार देखते हैं?
जॉन

1
यह वास्तव में बड़ी xml फ़ाइलों का मामला नहीं है (खदानें केवल 2-3kb से + 6mb तक जाती हैं), लेकिन इसके बजाय बहुत बड़ी संख्या में xml फाइलें हैं (हम यहां प्रति मिनट लगभग 10,000 xml अनुरोधों के बारे में बात कर रहे हैं); उस मामले में संदर्भ बनाने के लिए सिर्फ एक बार उन छोटे एमएस हासिल करने से बहुत बड़ा फर्क पड़ता है
tbarderas

1

मैं आमतौर पर ThreadLocalक्लास पैटर्न के साथ इस तरह की समस्याओं को हल करता हूं । इस तथ्य को देखते हुए कि आपको प्रत्येक वर्ग के लिए एक अलग singletonमार्शेलर की आवश्यकता है, आप इसे -मैप पैटर्न के साथ जोड़ सकते हैं ।

आपको 15 मिनट बचाने के लिए, काम का। यहाँ जैक्सब मार्शल और अनमरशैलर्स के लिए एक थ्रेड-सुरक्षित कारखाने के मेरे कार्यान्वयन का अनुसरण करता है।

यह आपको निम्नानुसार उदाहरणों का उपयोग करने की अनुमति देता है ...

Marshaller m = Jaxb.get(SomeClass.class).getMarshaller();
Unmarshaller um = Jaxb.get(SomeClass.class).getUnmarshaller();

और आपको जिस कोड की आवश्यकता होगी वह एक छोटी सी जैक्सब क्लास है जो इस प्रकार है:

public class Jaxb
{
  // singleton pattern: one instance per class.
  private static Map<Class,Jaxb> singletonMap = new HashMap<>();
  private Class clazz;

  // thread-local pattern: one marshaller/unmarshaller instance per thread
  private ThreadLocal<Marshaller> marshallerThreadLocal = new ThreadLocal<>();
  private ThreadLocal<Unmarshaller> unmarshallerThreadLocal = new ThreadLocal<>();

  // The static singleton getter needs to be thread-safe too, 
  // so this method is marked as synchronized.
  public static synchronized Jaxb get(Class clazz)
  {
    Jaxb jaxb =  singletonMap.get(clazz);
    if (jaxb == null)
    {
      jaxb = new Jaxb(clazz);
      singletonMap.put(clazz, jaxb);
    }
    return jaxb;
  }

  // the constructor needs to be private, 
  // because all instances need to be created with the get method.
  private Jaxb(Class clazz)
  {
     this.clazz = clazz;
  }

  /**
   * Gets/Creates a marshaller (thread-safe)
   * @throws JAXBException
   */
  public Marshaller getMarshaller() throws JAXBException
  {
    Marshaller m = marshallerThreadLocal.get();
    if (m == null)
    {
      JAXBContext jc = JAXBContext.newInstance(clazz);
      m = jc.createMarshaller();
      marshallerThreadLocal.set(m);
    }
    return m;
  }

  /**
   * Gets/Creates an unmarshaller (thread-safe)
   * @throws JAXBException
   */
  public Unmarshaller getUnmarshaller() throws JAXBException
  {
    Unmarshaller um = unmarshallerThreadLocal.get();
    if (um == null)
    {
      JAXBContext jc = JAXBContext.newInstance(clazz);
      um = jc.createUnmarshaller();
      unmarshallerThreadLocal.set(um);
    }
    return um;
  }
}

10
थ्रेडलोक बिना लाभ के, अन्य सूक्ष्म समस्याओं को पेश करेगा। बस एक ही JAXBContext (जो महंगा हिस्सा है) रखें और जब भी आवश्यकता हो एक नया Unmarshaller बनाएं।
यमजोरोस

आप वास्तव में अलग JAXBContexts की जरूरत नहीं है क्योंकि आप कई कक्षाओं में पास कर सकते हैं। तो, यदि आप अनुमान लगा सकते हैं कि कौन सी कक्षाएं मार्शेल्ड होने जा रही हैं, तो आप एक साझा एक बना सकते हैं। इसके अलावा, JAXB कल्पना के लिए उन्हें पहले से ही थ्रेडसेफ़ होना आवश्यक है।
20
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.