java जावा/मेवेन में "जेर्सेस नरक" से निपटना?




maven classloader (9)

मेरे कार्यालय में, ज़ीरिस शब्द का केवल उल्लेख ही डेवलपर्स से हत्यारा क्रोध को उकसाने के लिए पर्याप्त है। एसओ पर अन्य ज़ीरिस प्रश्नों पर एक सरसरी नज़र यह इंगित करती है कि लगभग सभी मैवेन उपयोगकर्ता इस समस्या से किसी भी समय "स्पर्श" कर रहे हैं। दुर्भाग्य से, समस्या को समझने के लिए Xerces के इतिहास के बारे में थोड़ा सा ज्ञान की आवश्यकता है ...

इतिहास

  • जावा पारिस्थितिक तंत्र में ज़र्सेस सबसे व्यापक रूप से उपयोग किया जाने वाला एक्सएमएल पार्सर है। जावा में लिखी गई लगभग हर लाइब्रेरी या फ्रेमवर्क कुछ क्षमता में एक्सरिस का उपयोग करती है (ट्रांजिटिवली, अगर सीधे नहीं)।

  • आधिकारिक बाइनरी में शामिल जेर्सेस जार इस दिन तक संस्करणित नहीं हैं। उदाहरण के लिए, Xerces 2.11.0 कार्यान्वयन जार का नाम xercesImpl.jar और xercesImpl-2.11.0.jar

  • जेर्सेस टीम मेवेन का उपयोग नहीं करती है , जिसका अर्थ है कि वे मेवेन सेंट्रल को आधिकारिक रिलीज अपलोड नहीं करते हैं।

  • Xerces को एक जार ( xerces.jar ) के रूप में रिलीज़ किया जाता था, लेकिन इसे दो जारों में विभाजित किया गया था, जिसमें एपीआई ( xml-apis.jar ) होता है और इनमें से एक एपीआई ( xercesImpl.jar ) के कार्यान्वयन होते हैं। कई पुराने मेवेन पीओएम अभी भी xerces.jar पर निर्भरता घोषित करते हैं। अतीत में किसी बिंदु पर, जेर्सेस को xmlParserAPIs.jar के रूप में भी जारी किया गया था, जो कुछ पुराने पीओएम भी निर्भर करते हैं।

  • एक्सएमएल-एपिस और xercesImpl जार को आवंटित संस्करण जो उनके जार को मैवेन रिपोजिटरी में तैनात करते हैं, अक्सर अलग होते हैं। उदाहरण के लिए, xml-apis को संस्करण 1.3.03 दिया जा सकता है और xercesImpl को संस्करण 2.8.0 दिया जा सकता है, भले ही दोनों Xerces 2.8.0 से हैं। ऐसा इसलिए होता है क्योंकि लोग अक्सर एक्सएमएल-एपिस जार को विनिर्देशों के संस्करण के साथ टैग करते हैं जो इसे लागू करता है। यहां एक बहुत अच्छा, लेकिन अपूर्ण टूटना here

  • मामलों को जटिल बनाने के लिए, जेरेस एक्सएमएल पार्सर है जो जेआरई में एक्सएमएल प्रोसेसिंग (जेएक्सपी) के लिए जावा एपीआई के संदर्भ कार्यान्वयन में उपयोग किया जाता है। कार्यान्वयन कक्षाओं को com.sun.* नेमस्पेस के तहत पुन: com.sun.* , जो उन्हें सीधे एक्सेस करने में खतरनाक बनाता है, क्योंकि वे कुछ जेआरई में उपलब्ध नहीं हो सकते हैं। हालांकि, java.* माध्यम से सभी जेरिस कार्यक्षमता का खुलासा नहीं किया जाता है java.* और javax.* एपीआई; उदाहरण के लिए, कोई एपीआई नहीं है जो Xerces serialization का खुलासा करती है।

  • भ्रमित गड़बड़ में जोड़ना, लगभग सभी सर्वलेट कंटेनर (जेबॉस, जेट्टी, ग्लासफ़िश, टोमकैट, इत्यादि), ज़ीरस के साथ एक या अधिक /lib फ़ोल्डर्स में शिप करते हैं।

समस्या का

संघर्ष समाधान

कुछ के लिए - या शायद सभी कारणों से, कई संगठन अपने पीओएम में जेरिस के कस्टम बिल्ड प्रकाशित और उपभोग करते हैं। यदि आपके पास एक छोटा सा एप्लीकेशन है और केवल मेवेन सेंट्रल का उपयोग कर रहा है, तो यह वास्तव में एक समस्या नहीं है, लेकिन यह एंटरप्राइज़ सॉफ़्टवेयर के लिए जल्दी ही एक मुद्दा बन जाता है जहां आर्टिफैक्टरी या नेक्सस कई रिपॉजिटरीज (जेबॉस, हाइबरनेट, इत्यादि) को प्रॉक्सी कर रहा है:

उदाहरण के लिए, संगठन ए xml-apis को प्रकाशित कर सकता है:

<groupId>org.apache.xerces</groupId>
<artifactId>xml-apis</artifactId>
<version>2.9.1</version>

इस बीच, संगठन बी एक ही jar को प्रकाशित कर सकता है:

<groupId>xml-apis</groupId>
<artifactId>xml-apis</artifactId>
<version>1.3.04</version>

हालांकि बी का jar ए के jar से कम संस्करण है, लेकिन मैवेन को यह नहीं पता कि वे एक ही कलाकृति हैं क्योंकि उनके पास अलग-अलग groupId । इस प्रकार, यह संघर्ष समाधान नहीं कर सकता है और दोनों jar एस को हल निर्भरताओं के रूप में शामिल किया जाएगा:

क्लासलोडर नरक

जैसा ऊपर बताया गया है, जेएआरपी आरआई में जेरेस के साथ जेआरई जहाजों। हालांकि सभी Xerces Maven निर्भरताओं को <exclusion> या <provided> रूप में चिह्नित करना अच्छा लगेगा, आप जिस तीसरे पक्ष के कोड पर निर्भर करते हैं, वह उस जेडीके के जेएक्सपी में प्रदान किए गए संस्करण के साथ काम कर सकता है या नहीं। इसके अलावा, आपके पास झुकाव जार आपके सर्वलेट कंटेनर में फंसने के लिए भेज दिया गया है। यह आपको कई विकल्पों के साथ छोड़ देता है: क्या आप सर्वलेट संस्करण को हटाते हैं और उम्मीद करते हैं कि आपका कंटेनर JAXP संस्करण पर चलता है? क्या सर्वलेट संस्करण छोड़ना बेहतर है, और उम्मीद है कि आपके एप्लिकेशन फ्रेमवर्क सर्वलेट संस्करण पर चलते हैं? यदि ऊपर उल्लिखित एक या दो अनसुलझे संघर्ष आपके उत्पाद (एक बड़े संगठन में होने में आसान) में फिसलने में कामयाब होते हैं, तो आप जल्दी ही क्लासलोडर नरक में पाते हैं, यह सोचकर कि क्लासलोडर का कौन सा संस्करण रनटाइम पर उठा रहा है और चाहे वह नहीं विंडोज और लिनक्स (शायद नहीं) में एक ही जार उठाएगा।

समाधान की?

हमने सभी जेरिस मेवेन निर्भरताओं को <provided> या <exclusion> रूप में चिह्नित करने का प्रयास किया है, लेकिन यह लागू करना मुश्किल है (विशेष रूप से एक बड़ी टीम के साथ) यह देखते हुए कि कलाकृतियों में इतने सारे उपनाम हैं ( xml-apis , xerces , xercesImpl , xmlParserAPIs , आदि)। इसके अतिरिक्त, हमारी तृतीय पक्ष libs / frameworks JAXP संस्करण या सर्वलेट कंटेनर द्वारा प्रदान किए गए संस्करण पर नहीं चल सकता है।

मैवेन के साथ हम इस समस्या को सबसे अच्छी तरह से कैसे संबोधित कर सकते हैं? क्या हमें अपनी निर्भरताओं पर इस तरह के बढ़िया नियंत्रण का उपयोग करना है, और फिर टायरेड क्लासलोडिंग पर भरोसा करना है? वैश्विक स्तर पर सभी ज़ीरस निर्भरताओं को बाहर करने का कोई तरीका है, और जेएक्सपी संस्करण का उपयोग करने के लिए हमारे सभी ढांचे / libs को मजबूर करता है?

अद्यतन : जोशुआ स्पिवाक ने XERCESJ-1454 में जेरिस बिल्ड स्क्रिप्ट्स का एक पैच संस्करण अपलोड किया है जो मैवेन सेंट्रल पर अपलोड करने की अनुमति देता है। इस मुद्दे पर वोट / देखें / योगदान दें और चलो इस समस्या को एक बार और सभी के लिए ठीक करें।


20 फरवरी 2013 से मेवेन सेंट्रल में xerces के 2.11.0 JARs (और स्रोत JARs !) हैं! मेवेन सेंट्रल में जेर्सेस देखें। मुझे आश्चर्य है कि उन्होंने XERCESJ-1454 समाधान क्यों नहीं किया है ...

मैंने उपयोग किया है:

<dependency>
    <groupId>xerces</groupId>
    <artifactId>xercesImpl</artifactId>
    <version>2.11.0</version>
</dependency>

और सभी निर्भरताओं ने ठीक हल किया है - यहां तक ​​कि उचित xml-apis-1.4.01 !

और सबसे महत्वपूर्ण क्या है (और अतीत में क्या स्पष्ट नहीं था) - Xerces-J-bin.2.11.0.zip सेंट्रल में जार एक ही जार है जो आधिकारिक Xerces-J-bin.2.11.0.zip . Xerces-J-bin.2.11.0.zip वितरण में है

हालांकि मुझे xml-schema-1.1-beta संस्करण नहीं मिला - यह अतिरिक्त निर्भरताओं के कारण मेवेन classifier xml-schema-1.1-beta संस्करण नहीं हो सकता है।


हर मेवेन प्रोजेक्ट को xerces के आधार पर रोकना चाहिए, शायद वे वास्तव में नहीं हैं। एक्सएमएल एपीआई और एक आईपीएल 1.4 के बाद से जावा का हिस्सा रहा है। Xerces या XML एपीआई पर निर्भर रहने की कोई आवश्यकता नहीं है, ऐसा कहने की तरह आप जावा या स्विंग पर निर्भर करते हैं। यह निहित है।

अगर मैं एक मैवेन रेपो का मालिक था, तो मैं ज़ीरस निर्भरताओं को दोबारा हटाने के लिए एक स्क्रिप्ट लिखूंगा और मुझे एक पढ़ना लिखूंगा जो कहता है कि इस रेपो को जावा 1.4 की आवश्यकता है।

कुछ भी जो वास्तव में टूटता है क्योंकि यह सीधे xgces को org.apache आयात के माध्यम से संदर्भित करता है, इसे जावा 1.4 स्तर (और 2002 से किया गया है) तक पहुंचने के लिए कोड फिक्स की आवश्यकता होती है या अनुमोदित libs के माध्यम से JVM स्तर पर समाधान, मैवेन में नहीं।


आप प्रतिबंधित निर्भरता नियम के साथ मेवेन एनफोर्स प्लगइन का उपयोग कर सकते हैं। यह आपको उन सभी उपनामों पर प्रतिबंध लगाने की अनुमति देगा जो आप नहीं चाहते हैं और केवल वही चाहते हैं जो आप चाहते हैं। उल्लंघन के दौरान ये नियम आपकी परियोजना के मेवेन निर्माण को विफल कर देंगे। इसके अलावा, यदि यह नियम किसी एंटरप्राइज़ में सभी प्रोजेक्ट्स पर लागू होता है तो आप कॉर्पोरेट पेरेंट पोम में प्लगइन कॉन्फ़िगरेशन डाल सकते हैं।

देख:


एक और विकल्प है जिसे यहां खोजा नहीं गया है: वैकल्पिक रूप से मेवेन में ज़ेरेस निर्भरता घोषित करना:

<dependency>
   <groupId>xerces</groupId>
   <artifactId>xercesImpl</artifactId>
   <version>...</version>
   <optional>true</optional>
</dependency>

असल में यह है कि सभी आश्रितों को ज़ेरेस के अपने संस्करण की घोषणा करने के लिए मजबूर करना है या उनकी परियोजना संकलित नहीं होगी। अगर वे इस निर्भरता को ओवरराइड करना चाहते हैं, तो ऐसा करने के लिए उनका स्वागत है, लेकिन फिर वे संभावित समस्या का मालिक बनेंगे।

यह डाउनस्ट्रीम परियोजनाओं के लिए एक मजबूत प्रोत्साहन बनाता है:

  • एक सक्रिय निर्णय लें। क्या वे ज़ेरिस के उसी संस्करण के साथ जाते हैं या कुछ और उपयोग करते हैं?
  • असल में अपने पार्सिंग का परीक्षण करें (उदाहरण के लिए यूनिट परीक्षण के माध्यम से) और क्लासलोडिंग के साथ-साथ अपने क्लासपाथ को अव्यवस्थित नहीं करना।

सभी डेवलपर्स नए पेश किए गए निर्भरताओं का ट्रैक नहीं रखते हैं (उदाहरण के लिए mvn dependency:tree )। यह दृष्टिकोण तत्काल इस मामले को उनके ध्यान में लाएगा।

यह हमारे संगठन में काफी अच्छा काम करता है। इसकी शुरूआत से पहले, हम उसी नरक में रहते थे जो ओपी वर्णन कर रहा था।


मेरा दोस्त बहुत सरल है, यहां एक उदाहरण है:

<dependency>
            <groupId>xalan</groupId>
            <artifactId>xalan</artifactId>
            <version>2.7.2</version>
            <scope>${my-scope}</scope>
            <exclusions>
                <exclusion>
                    <groupId>xml-apis</groupId>
                    <artifactId>xml-apis</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

और यदि आप टर्मिनल में जांचना चाहते हैं (इस उदाहरण के लिए विंडोज कंसोल) कि आपके मेवेन पेड़ में कोई समस्या नहीं है:

mvn dependency:tree -Dverbose | grep --color=always '(.* conflict\|^' | less -r

मॉड्यूलर निर्भरताओं को छोड़कर, छोड़ने के अलावा, क्या मदद करेगा।

एक फ्लैट क्लासलोडिंग (स्टैंडअलोन ऐप), या सेमी-पदानुक्रमिक (जेबॉस एएस / ईएपी 5.x) के साथ यह एक समस्या थी।

लेकिन OSGi और जेबॉस मॉड्यूल जैसे मॉड्यूलर ढांचे के साथ, यह अब इतना दर्द नहीं है। लाइब्रेरी स्वतंत्र रूप से जो भी लाइब्रेरी चाहते हैं, उनका उपयोग कर सकते हैं।

बेशक, यह अभी भी एक ही कार्यान्वयन और संस्करण के साथ चिपकने के लिए सबसे अधिक अनुशंसित है, लेकिन यदि कोई अन्य तरीका नहीं है (अधिक libs से अतिरिक्त सुविधाओं का उपयोग करके), तो मॉड्यूलरिंग आपको बचा सकता है।

कार्रवाई में जेबॉस मॉड्यूल का एक अच्छा उदाहरण स्वाभाविक रूप से, जेबॉस एएस 7 / ईएपी 6 / वाइल्डफ्ली 8 है , जिसके लिए इसे मुख्य रूप से विकसित किया गया था।

उदाहरण मॉड्यूल परिभाषा:

<?xml version="1.0" encoding="UTF-8"?>
<module xmlns="urn:jboss:module:1.1" name="org.jboss.msc">
    <main-class name="org.jboss.msc.Version"/>
    <properties>
        <property name="my.property" value="foo"/>
    </properties>
    <resources>
        <resource-root path="jboss-msc-1.0.1.GA.jar"/>
    </resources>
    <dependencies>
        <module name="javax.api"/>
        <module name="org.jboss.logging"/>
        <module name="org.jboss.modules"/>
        <!-- Optional deps -->
        <module name="javax.inject.api" optional="true"/>
        <module name="org.jboss.threads" optional="true"/>
    </dependencies>
</module>

ओएसजीआई की तुलना में, जेबॉस मॉड्यूल सरल और तेज़ है। कुछ विशेषताओं को याद करते समय, यह ज्यादातर परियोजनाओं के लिए पर्याप्त है (ज्यादातर) एक विक्रेता के नियंत्रण में हैं, और तेज तेज बूट (पैरालाइज्ड निर्भरताओं को हल करने के कारण) की अनुमति देते हैं।

ध्यान दें कि जावा 8 के लिए एक मॉड्यूलरलाइजेशन प्रयास चल रहा है , लेकिन AFAIK मुख्य रूप से जेआरई को मॉड्यूलर करने के लिए है, यह सुनिश्चित नहीं है कि यह ऐप्स पर लागू होगा या नहीं।


मुझे पता है कि यह वास्तव में सवाल का जवाब नहीं देता है, लेकिन पीपीएल के लिए Google से आ रहा है जो उनके निर्भरता प्रबंधन के लिए ग्रैडल का उपयोग करने के लिए होता है:

मैं इस तरह के ग्रैडल के साथ सभी xerces / Java8 मुद्दों से छुटकारा पाने में कामयाब रहा:

configurations {
    all*.exclude group: 'xml-apis'
    all*.exclude group: 'xerces'
}

एक्सएमएल नरक के अपने स्तर की पहचान करने में मदद के लिए आपको पहले डीबग करना चाहिए। मेरी राय में, पहला कदम जोड़ना है

-Djavax.xml.parsers.SAXParserFactory=com.sun.org.apache.xerces.internal.jaxp.SAXParserFactoryImpl
-Djavax.xml.transform.TransformerFactory=com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl
-Djavax.xml.parsers.DocumentBuilderFactory=com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderFactoryImpl

कमांड लाइन के लिए। यदि यह काम करता है, तो पुस्तकालयों को छोड़ना शुरू करें। यदि नहीं, तो जोड़ें

-Djaxp.debug=1

कमांड लाइन के लिए।


मुझे लगता है कि एक प्रश्न है जिसे आपको जवाब देने की आवश्यकता है:

क्या कोई xerces * .jar मौजूद है जो आपके एप्लिकेशन में सबकुछ के साथ रह सकता है?

यदि नहीं, तो आप मूल रूप से खराब हो जाते हैं और ओएसजीआई जैसे कुछ का उपयोग करना होगा, जो आपको एक ही समय में लोड लाइब्रेरी के विभिन्न संस्करणों की अनुमति देता है। चेतावनी दीजिये कि यह मूल रूप से क्लासलोडर मुद्दों के साथ जार संस्करण मुद्दों को प्रतिस्थापित करता है ...

यदि ऐसा कोई संस्करण मौजूद है तो आप अपने भंडार को सभी प्रकार की निर्भरताओं के लिए उस संस्करण को वापस कर सकते हैं। यह एक बदसूरत हैक है और आपके क्लासपाथ में एक ही xerces कार्यान्वयन के साथ कई बार समाप्त होगा लेकिन xerces के कई अलग-अलग संस्करण होने से बेहतर होगा।

आप प्रत्येक निर्भरता को xerces में बहिष्कृत कर सकते हैं और उस संस्करण में जोड़ सकते हैं जिसका आप उपयोग करना चाहते हैं।

मुझे आश्चर्य है कि क्या आप किसी प्रकार की संस्करण रिज़ॉल्यूशन रणनीति को मैवेन के लिए प्लगइन के रूप में लिख सकते हैं। यह शायद सबसे अच्छा समाधान होगा, लेकिन यदि संभव हो तो कुछ शोध और कोडिंग की आवश्यकता है।

आपके रनटाइम पर्यावरण में निहित संस्करण के लिए, आपको यह सुनिश्चित करना होगा कि इसे या तो एप्लिकेशन क्लासपाथ से हटा दिया गया हो या एप्लिकेशन जार को सर्वर के lib फ़ोल्डर से पहले क्लासलोडिंग के लिए पहले माना जाता है।

तो इसे लपेटने के लिए: यह एक गड़बड़ है और वह नहीं बदलेगा।





xerces