2013-10-29 30 views
36

जब एक Maven परियोजना कई निर्भरता है कि निर्माण में परस्पर विरोधी पुस्तकालय संस्करण, उन निर्भरता के कुछ ही पुस्तकालय पर निर्भर करते हैं, लेकिन जो त्रुटियों खड़ी कर रहा है जब एक आवेदन चल रहा है एक अलग संस्करण का उपयोग करें।एक जावा Maven परियोजना

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

लेकिन बी के बाईटकोड कई समस्याओं के कारण एप्लिकेशन चलते समय लोड वर्गों में से एक अलग संस्करण पर निर्भर करता है। एक आम तरीका methodnotfound अपवाद है (क्योंकि http क्लाइंट का ए संस्करण अब एक विशिष्ट विधि का उपयोग नहीं करता है)। सामान्य रणनीति जब इस तरह के टकराव से बचने के निर्माण

क्या है? क्या किसी को आम तौर पर एक दूसरे के साथ कॉल करने के लिए आम पुस्तकालयों को समझने के लिए निर्भरता पेड़ की जांच करनी पड़ती है?

उत्तर

22

maven dependency hell में आपका स्वागत है, क्योंकि यह जानबूझकर जाना जाता है। यह कुछ हद तक आम समस्या है क्योंकि परियोजनाएं बढ़ती हैं और अधिक बाहरी निर्भरताएं पेश की जाती हैं।

अपाचे कॉमन्स (अपने मूल प्रश्न में उल्लेख किया है) इसके अलावा, प्रवेश करने चौखटे (log4j, slf4j) एक और बार-बार समस्या हैं।

मैं पहचान के बाद संघर्षों को हल करने के तरीके पर "मैट्स" द्वारा दी गई सलाह से सहमत हूं। इन संस्करणों को जल्दी से पकड़ने के मामले में, आप मेवेन "एनफोर्सर" प्लगइन का भी उपयोग कर सकते हैं। "dependencyConvergence" config का संदर्भ लें। this SO post भी देखें।

एंफोर्स प्लगइन का उपयोग करना संस्करण संघर्ष पर तुरंत निर्माण में विफल हो जाएगा, जो आपको मैन्युअल चेक से बचाता है।यह एक आक्रामक रणनीति है, लेकिन आपके प्रश्न/पद को प्रेरित करने वाली रन-टाइम समस्याओं के प्रकार को रोकती है। कुछ भी पसंद है, Enforcer प्लगइन पेशेवरों और विपक्ष है। हमने पिछले साल के भीतर इसका उपयोग शुरू किया, लेकिन फिर पता चला कि यह एक आशीर्वाद और शाप हो सकता है। Libs/frameworks के कई संस्करण पीछे संगत हैं, और इसलिए संस्करण 1.2.3 और 1.2.4 दोनों पर निर्भर करता है (चाहे प्रत्यक्ष या परोक्ष रूप से) दोनों संकलन-समय और रन-टाइम पर अक्सर ठीक है। हालांकि, एंटरप्राइज़ प्लगइन इस संघर्ष को ध्वजांकित करेगा और आपको यह घोषणा करने की आवश्यकता होगी कि आप कौन सा संस्करण चाहते हैं। निर्भरता की संख्या मानना-संघर्ष छोटा है, इसके लिए अधिक काम की आवश्यकता नहीं है। हालांकि, एक बार जब आप एक बड़े ढांचे (उदाहरण के लिए स्प्रिंग एमवीसी) पेश करते हैं तो यह बुरा हो सकता है।

उम्मीद है कि यह उपयोगी जानकारी है।

33

आप अपने प्रोजेक्ट में सभी ट्रांजिटिव निर्भरताओं को प्रदर्शित करने के लिए मेवेन निर्भरता प्लगइन के tree goal का उपयोग कर सकते हैं और "संघर्ष के लिए छोड़े गए" निर्भरताओं की तलाश कर सकते हैं। 1

mvn dependency:tree -Dverbose 
mvn dependency:tree -Dverbose | grep 'omitted for conflict' 

एक बार जब आप जानते हैं कि कौन निर्भरता संस्करण संघर्ष है, तो आपको includes पैरामीटर सिर्फ इतना है कि एक पर लेकर जाते निर्भरता को देखने के लिए कैसे एक विशेष निर्भरता में खींचा जा रहा है दिखाने के लिए एक परियोजना है, जहां विभिन्न उपयोग कर सकते हैं। उदाहरण के लिए, सी के संस्करणों ए और बी से में खींच रहे हैं:

mvn dependency:tree -Dverbose -Dincludes=project-c 

[INFO] com.my-company:my-project:jar:1.0-SNAPSHOT 
[INFO] +- project-a:project-a:jar:0.1:compile 
[INFO] | \- project-c:project-c:jar:1.0:compile 
[INFO] \- project-b:project-b:jar:0.2:compile 
[INFO] \- project-x:project-x:jar:0.1:compile 
[INFO]  \- (project-c:project-c:jar:2.0:compile - omitted for conflict) 

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

हालांकि, अन्य मामलों में यह संभव नहीं निर्भरता जो सभी के लिए के एक संस्करण को खोजने के लिए हो सकता है। इन मामलों में, आपको प्राथमिक निर्भरताओं में से किसी एक पर संस्करण को वापस लेना पड़ सकता है ताकि इसे सभी के लिए काम करने वाले पारस्परिक निर्भरता के संस्करण का उपयोग किया जा सके। उदाहरण के लिए, ऊपर दिए गए उदाहरण में, ए 0.1 सी 1.0 का उपयोग करता है और बी 0.2 सी 2.0 का उपयोग करता है। मान लीजिए सी 1.0 और 2.0 पूरी तरह से असंगत हैं। लेकिन शायद आपके प्रोजेक्ट के लिए बी 0.1 का उपयोग करना संभव है, जो सी 1.5 पर निर्भर करता है, जो सी 1.0 के साथ संगत है।

बेशक इन दो रणनीतियों हमेशा काम नहीं करेगा, लेकिन मैं इससे पहले कि उन लोगों के साथ सफलता मिली है। अन्य अधिक कठोर विकल्पों में निर्भरता का अपना संस्करण पैकेजिंग शामिल है जो असंगतता को हल करता है या अलग-अलग वर्गीकरण में दो निर्भरताओं को अलग करने की कोशिश करता है।

+0

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

+2

मैट्स द्वारा सही जवाब। मेरे लिए मैंने एक प्रश्न के साथ छोड़ा, क्यों विभिन्न संस्करणों के साथ कई जार एक साथ मौजूद नहीं हो सकते हैं? क्यों मॉड्यूल एक्स के संस्करण 0.1 के लिंक को मॉड्यूल बी के साथ लाइव नहीं करता है जो एक्स के संस्करण 0.2 से लिंक करता है? उत्तर है -> वर्ग के नाम के कारण: "वर्चुअल मशीन में लोड होने वाली प्रत्येक कक्षा को तीन चीजों द्वारा विशिष्ट रूप से पहचाना जाता है। इसका नाम, इसका पैकेज और इसका वर्ग लोडर।" से: https://kepler-project.org/developers/teams/framework/design-docs/trade-studies/custom-class-loading/using-multiple-classloaders। – Robocide

1

मैं इस तथ्य के साथ टोड की और Matts के उत्तरों का विस्तार करने के आप कर सकते हैं कि चाहते हैं:

  • mvn dependency:tree -Dverbose -Dincludes=project-c

  • अपने सभी निर्भरता जो project-c की एक सकर्मक निर्भरता के लिए एक <exclusions/> टैग जोड़ें।

  • या, वैकल्पिक रूप से, आपके प्रोजेक्ट के अंदर, संक्रमित लोगों को ओवरराइड करने और संघर्ष से बचने के लिए स्पष्ट रूप से project-c को निर्भरता के रूप में परिभाषित करें। (यह अभी भी '-Dverbose) का उपयोग करते समय आपके पेड़ में दिखाएगा।

वैकल्पिक रूप से, अगर उन परियोजनाओं अपने नियंत्रण में हैं, तो आप बस project-c के संस्करण को अपग्रेड कर सकते हैं।

1

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

यह मेरे लिए काम करता है, और मैं संस्करणों को मिलान करने में सक्षम था। यदि आप संस्करणों को बदलने में असमर्थ हैं, तो यह बहुत उपयोगी नहीं होगा।

Dependency Convergence

<project> 
... 
    <build> 
    <plugins> 
     ... 
     <plugin> 
     <groupId>org.apache.maven.plugins</groupId> 
     <artifactId>maven-enforcer-plugin</artifactId> 
     <version>1.4</version> 
     <executions> 
      <execution> 
      <id>enforce</id> 
      <configuration> 
       <rules> 
       <dependencyConvergence/> 
       </rules> 
      </configuration> 
      <goals> 
       <goal>enforce</goal> 
      </goals> 
      </execution> 
     </executions> 
     </plugin> 
     ... 
    </plugins> 
    </build> 
    ... 
</project> 

निर्भरता कोष्ठक का उपयोग पर एक संस्करण के लिए मजबूर:

<dependency> 
     <groupId>org.slf4j</groupId> 
     <artifactId>slf4j-api</artifactId> 
     <scope>compile</scope> 
     <version>[1.0.0]</version> 
</dependency> 
संबंधित मुद्दे