ग्रेड कार्यान्वयन बनाम एपीआई कॉन्फ़िगरेशन


231

मैं यह पता लगाने की कोशिश कर रहा हूं कि मेरी निर्भरता के निर्माण के दौरान apiऔर implementationकॉन्फ़िगरेशन में क्या अंतर है ।
प्रलेखन में, यह कहता है कि implementationबेहतर निर्माण समय है, लेकिन, इस टिप्पणी को एक समान प्रश्न में देखकर मुझे आश्चर्य हुआ कि क्या यह सच है।
चूंकि मैं वर्गीकृत करने में कोई विशेषज्ञ नहीं हूं, मुझे आशा है कि कोई मदद कर सकता है। मैंने पहले ही प्रलेखन पढ़ा है, लेकिन मैं एक आसान-से-समझा स्पष्टीकरण के बारे में सोच रहा था।


1
क्या आपने यहाँ पढ़ा है ?
MatPag

तथ्य की बात के रूप में, मैंने किया, लेकिन, जैसा कि मैंने कहा, उस टिप्पणी ने इसके बारे में आश्चर्यचकित कर दिया। तो मैं
थोरा

आप शायद से अपने पुस्तकालयों निर्भरता स्विच करेंगे compileकरने के लिए api। जो पुस्तकालय आप आंतरिक रूप से उपयोग करते हैं वे कुछ निजी कार्यान्वयन का उपयोग कर सकते हैं जो अंतिम पुस्तकालय में उजागर नहीं होते हैं इसलिए वे आपके लिए पारदर्शी हैं। उन "आंतरिक-निजी" निर्भरता पर स्विच किया जा सकता है implementationऔर जब एंड्रॉइड ग्रेडल प्लगइन आपके ऐप को संकलित करेगा, तो यह उन निर्भरता के संकलन को छोड़ देगा जिसके परिणामस्वरूप एक छोटा निर्माण समय होगा (लेकिन वे निर्भरता रनटाइम पर उपलब्ध होंगी)। जाहिर है आप वही काम कर सकते हैं यदि आपके पास स्थानीय मॉड्यूल लाइब्रेरी है
MatPag

1
यहाँ ' आपी
albert c braun

1
यह एक बढ़िया पोस्ट है! साभार @albertbraun
reinaldomoreira

जवाबों:


418

ग्रेडेल compileकीवर्ड निर्भरता को कॉन्फ़िगर करने के लिए apiऔर implementationकीवर्ड के पक्ष में हटा दिया गया था ।

उपयोग करना apiपदावनत का उपयोग करने के बराबर है compile, इसलिए यदि आप सभी compileको apiहर चीज से प्रतिस्थापित करते हैं तो हमेशा की तरह काम करेंगे।

implementationकीवर्ड को समझने के लिए निम्नलिखित उदाहरण पर विचार करें।

उदाहरण

मान लीजिए कि आपके पास एक पुस्तकालय है जिसे MyLibraryआंतरिक रूप से एक अन्य पुस्तकालय कहा जाता है InternalLibrary। कुछ इस तरह:

    // 'InternalLibrary' module
    public class InternalLibrary {
        public static String giveMeAString(){
            return "hello";
        }
    }
    // 'MyLibrary' module
    public class MyLibrary {
        public String myString(){
            return InternalLibrary.giveMeAString();
        }
    }

मान लीजिए इस तरह से कॉन्फ़िगरेशन का MyLibrary build.gradleउपयोग करता apiहै dependencies{}:

dependencies {
    api project(':InternalLibrary')
}

आप MyLibraryअपने कोड में उपयोग करना चाहते हैं ताकि आपके ऐप में build.gradleआप इस निर्भरता को जोड़ दें:

dependencies {
    implementation project(':MyLibrary')
}

apiकॉन्फ़िगरेशन का उपयोग करना (या पदावनत compile) आप InternalLibraryअपने आवेदन कोड में पहुंच सकते हैं :

// Access 'MyLibrary' (granted)
MyLibrary myLib = new MyLibrary();
System.out.println(myLib.myString());

// Can ALSO access the internal library too (and you shouldn't)
System.out.println(InternalLibrary.giveMeAString());

इस तरह से मॉड्यूल MyLibraryसंभावित रूप से किसी चीज के आंतरिक कार्यान्वयन को "लीक" कर रहा है। आपको इसका उपयोग नहीं करना चाहिए (क्योंकि यह आपके द्वारा सीधे आयात नहीं किया गया है)

implementationविन्यास इसे रोकने के लिए शुरू की गई थी। तो अब अगर आप का उपयोग implementationकरने के बजाय apiमें MyLibrary:

dependencies {
    implementation project(':InternalLibrary')
}

अब आप InternalLibrary.giveMeAString()अपने ऐप कोड में कॉल नहीं कर पाएंगे ।

मुक्केबाजी रणनीति इस तरह एंड्रॉयड Gradle पता चला है कि अगर आप में कुछ संपादित प्लगइन की अनुमति देता है InternalLibrary, यह केवल की रखता को गति प्रदान करना चाहिए MyLibraryऔर नहीं अपने पूरे अनुप्रयोग के रखता है, क्योंकि आप के लिए पहुँच नहीं है InternalLibrary

जब आपके पास बहुत अधिक नेस्टेड निर्भरता होती है, तो यह तंत्र बिल्ड को बहुत तेज कर सकता है। (इसकी पूरी समझ के लिए वीडियो को अंत में देखें)

निष्कर्ष

  • जब आप नए एंड्रॉइड ग्रैगल प्लगइन 3.XX पर स्विच करते हैं, तो आपको अपने सभी compileको implementationकीवर्ड (1 *) से बदलना चाहिए । फिर अपने ऐप को कंपाइल और टेस्ट करने की कोशिश करें। यदि सब कुछ ठीक है तो कोड को छोड़ दें, यदि आपके पास समस्याएं हैं, तो आपके पास शायद आपकी निर्भरता के साथ कुछ गलत है या आपने कुछ ऐसा उपयोग किया है जो अब निजी है और अधिक सुलभ नहीं है। एंड्रॉइड ग्रैडल प्लगइन इंजीनियर जेरोम डोचेज़ द्वारा सुझाव (1 ) * )

  • यदि आप एक लाइब्रेरी मेन्टेनर हैं, तो आपको apiप्रत्येक निर्भरता के लिए उपयोग करना चाहिए जो आपके पुस्तकालय के सार्वजनिक एपीआई के लिए आवश्यक है, जबकि implementationपरीक्षण निर्भरता या निर्भरता के लिए उपयोग करें जो अंतिम उपयोगकर्ताओं द्वारा उपयोग नहीं की जानी चाहिए।

उपयोगी लेख कार्यान्वयन और एपीआई के बीच अंतर को दर्शाता है

संदर्भ (यह समय बचाने के लिए एक ही वीडियो है)

Google I / O 2017 - ग्रैडल कैसे तेजी से बढ़ता है (पूर्ण वीडियो)

Google I / O 2017 - ग्रैडल कैसे बनता है (NEW GRADLE PLUGIN 3.0.0 PART ON मात्र)

Google I / O 2017 - ग्रैडल कैसे बनता है ( 1 * का संदर्भ )

Android प्रलेखन


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

1
यह ठीक है और डिबग-बिल्ड पर काम करता है लेकिन जब प्रोगार्ड (रिलीज-संस्करण पर) MyLibrary#myString()का उपयोग दुर्घटनाग्रस्त हो जाएगा क्योंकि प्रोगार्ड को InternalLibraryहटा दिया जाएगा । ProGuard'ed एप्लिकेशन में उपयोग किए जाने वाले Android-lib के लिए सबसे अच्छा अभ्यास क्या है?
हार्डसाइज

3
मुझे लगता है कि उत्तर सटीक नहीं है, एप्लिकेशन MyLibrary के लिए जो भी गुंजाइश चाहता है, उसका उपयोग कर सकता है। यह देखेंगी या नहीं कि इन मायलाइलुअर्स एपि / इंप्लीमेंटेशन का उपयोग करता है या नहीं, यह इंटरनललाइंस के आधार पर होगा।
Snicolas

2
धन्यवाद दोस्त। भयानक विवरण, एंड्रॉइड के आधिकारिक डॉक्स में दिए गए एक से बहुत बेहतर
हेनरी

2
यह एक सुंदर व्याख्या है। सिद्धांत और ठोस शानदार ढंग से मिश्रित। बहुत बढ़िया। इसके लिए धन्यवाद
पीटर कहन

133

मैं एक apiनिर्भरता के बारे में सार्वजनिक (अन्य मॉड्यूल द्वारा देखा गया) के बारे में सोचना पसंद करता हूं, जबकि implementationनिर्भरता निजी (केवल इस मॉड्यूल द्वारा देखी गई) है।

ध्यान दें, कि विपरीत public/ privateचर और विधियाँ, api/ implementationनिर्भरता रनटाइम द्वारा लागू नहीं की जाती हैं। यह केवल एक बिल्ड-टाइम ऑप्टिमाइज़ेशन है, Gradleजो यह जानने की अनुमति देता है कि किसी एक निर्भरता के एपीआई को बदलने पर उसे कौन से मॉड्यूल्स को फिर से स्थापित करने की आवश्यकता है।


15
इस उत्तर की सादगी से प्यार करें, बहुत बहुत धन्यवाद
केविन गिल्स 10

2
वास्तविक अंतर (AFAICT) यह है कि उत्पन्न पोम फ़ाइल api"संकलन" दायरे में निर्भरता को बढ़ाती है (वे आपके पुस्तकालय में निर्भरता के रूप में और कुछ भी जो आपके पुस्तकालय पर निर्भर करता है) और implementation"रनटाइम" दायरे में निर्भरता को शामिल किया जाएगा (वे इस पर बेहतर हैं) क्लासपैथ जब आपका कोड चल रहा होता है, लेकिन उन्हें आपके लाइब्रेरी का उपयोग करने वाले अन्य कोड को संकलित करने की आवश्यकता नहीं होती है)।
शैडो मैन

@ShadowMan यह प्लगइन के एक कार्यान्वयन विस्तार, पोम फ़ाइल पैदा करने, यह कैसे नक्शे के लिए जिम्मेदार है Gradle को scopes Maven स्कोप।
dev.bmax

1
आपको implementationकिसी भी निर्भरता के लिए उपयोग करना चाहिए जिसे चलाने के लिए (और आपके पुस्तकालय को संकलित करने के लिए) आवश्यक है, लेकिन यह आपके पुस्तकालय का उपयोग करने वाली परियोजनाओं में स्वचालित रूप से नहीं खींचा जाना चाहिए। एक उदाहरण jax-rs होगा, आपकी लाइब्रेरी RESTeasy का उपयोग कर सकती है, लेकिन यह किसी भी प्रोजेक्ट में उन कामों को नहीं खींचना चाहिए जो आपकी लाइब्रेरी का उपयोग करते हैं, क्योंकि वे शायद जर्सी का उपयोग करना चाहते हैं।
शैडो मैन

1
यह है कि आप जानते हैं कि किसी को इसका सामान मिलता है: डी सरल और स्पष्ट उत्तर के लिए धन्यवाद
इलायस फज़ल

12

विचार करें कि आपके पास appमॉड्यूल है जो lib1लाइब्रेरी के रूप में lib1उपयोग करता है और लाइब्रेरी के lib2रूप में उपयोग करता है । कुछ इस तरह app -> lib1 -> lib2:।

अब जब उपयोग कर api lib2रहे हैं lib1, तब कोड का उपयोग करते समय app देख सकते हैं lib2 :api lib1 या implementation lib1में appमॉड्यूल।

लेकिन का उपयोग करते समय implementation lib2में lib1, तो app नहीं देख सकते हैंlib2 कोड।


5

@ दटपट और @ देव-बमैक्स से जवाब स्पष्ट पर्याप्त हैं लोग कार्यान्वयन और एपीआई के बीच विभिन्न उपयोगों समझते हैं। मैं सिर्फ दूसरे कोण से एक अतिरिक्त व्याख्या करना चाहता हूं, लोगों के लिए मदद करने की उम्मीद करता है जिनके पास एक ही सवाल है।

मैंने परीक्षण के लिए दो प्रोजेक्ट बनाए:

  • प्रोजेक्ट A एक जावा लाइब्रेरी प्रोजेक्ट के रूप में जिसका नाम 'चौखटे-वेब-ग्रेड-प्लगइन' है, जो 'org.springframework.boot: स्प्रिंग-बूट-ग्रेड-प्लगइन: 1.5.20.RELEASE' पर निर्भर करता है
  • प्रोजेक्ट B कार्यान्वयन 'A.example.frameworks.gradle' के आधार पर प्रोजेक्ट A पर निर्भर करता है: चौखटे-वेब-ग्रेड-प्लगइन: 0.0.1-SNAPSHOT '

ऊपर बताई गई निर्भरता पदानुक्रम इस प्रकार है:

[प्रोजेक्ट-बी] -> [प्रोजेक्ट-ए] -> [स्प्रिंग-बूट-ग्रेड-प्लगइन]

तब मैंने निम्नलिखित परिदृश्यों का परीक्षण किया:

  1. द्वारा मेक परियोजना ए '1.5.20.RELEASE: वसंत-बूट-Gradle-प्लगइन org.springframework.boot' पर निर्भर करता है कार्यान्वयन

    gradle dependenciesनिम्नलिखित आउटपुट स्क्रीनशॉट के साथ poject B root dir command में टर्मिनल में रन कमांड हम देख सकते हैं कि runtimeClasspath निर्भरता ट्री में 'स्प्रिंग-बूट-ग्रेड-प्लगइन' दिखाई देता है, लेकिन compileClasspath's में नहीं, मुझे लगता है कि हम वास्तव में ऐसा नहीं कर सकते हैं पुस्तकालय का उपयोग जो कार्यान्वयन का उपयोग करते हुए घोषित किया गया है, यह सिर्फ संकलन के माध्यम से नहीं होगा।

    यहां छवि विवरण दर्ज करें

  2. द्वारा मेक परियोजना एक पर निर्भर करता है '1.5.20.RELEASE org.springframework.boot: वसंत-बूट-Gradle-प्लगइन' api

    gradle dependenciesपॉज़िशन में टर्मिनल में कमांड रन करें B रूट dir फिर से। अब 'स्प्रिंग-बूट-ग्रेड-प्लगइन' कंपाइलक्लासपथ और रनटाइमक्लासपैथ निर्भरता पेड़ दोनों में दिखाई देता है।

    यहां छवि विवरण दर्ज करें

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


2

से Gradle प्रलेखन :

आइए एक नज़र डालते हैं एक JVM- आधारित प्रोजेक्ट के लिए एक बहुत ही सरल बिल्ड स्क्रिप्ट पर।

plugins {
    id 'java-library'
}

repositories {
    mavenCentral()
}

dependencies {
    implementation 'org.hibernate:hibernate-core:3.6.7.Final'
    api 'com.google.guava:guava:23.0'
    testImplementation 'junit:junit:4.+'
}

कार्यान्वयन

परियोजना के उत्पादन स्रोत को संकलित करने के लिए आवश्यक निर्भरताएँ जो परियोजना द्वारा उजागर एपीआई का हिस्सा नहीं हैं। उदाहरण के लिए परियोजना अपने आंतरिक दृढ़ता परत कार्यान्वयन के लिए हाइबरनेट का उपयोग करती है।

एपीआई

परियोजना के उत्पादन स्रोत को संकलित करने के लिए आवश्यक निर्भरताएं जो परियोजना द्वारा उजागर एपीआई का हिस्सा हैं। उदाहरण के लिए परियोजना अमरूद का उपयोग करती है और अपने तरीके से हस्ताक्षर में अमरूद वर्गों के साथ सार्वजनिक इंटरफेस को उजागर करती है।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.