2012-11-06 6 views
9

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

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

  1. कॉन्फ़िगर() विधि में बाध्यकारी। इस विधि को इंजेक्शन नहीं दिया गया है और मुझे बेस कॉन्फ़िगरेशन नहीं मिल रहा है।

  2. प्रदाता/@ प्रदान करता है। प्रदाता केवल एक ही उदाहरण बांधते हैं।

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

  4. एक बच्चे इंजेक्टर का प्रयोग करें। दुर्भाग्य से मौजूदा कोड के कुछ व्यापक संशोधन के बिना यह संभव नहीं है। This answer इस समस्या को हल करने के तरीके के बारे में बहुत अच्छा वर्णन है।

  5. किसी भी तरह बाइंडर इंजेक्ट करें। (मुझे थोड़ा हैकर प्राप्त करना शुरू हुआ) गुइस इंजेक्टर को बाद के उपयोग के लिए इंजेक्शन देने की इजाजत देता है, मैंने मॉड्यूल में बाइंडर को इंजेक्शन करने की कोशिश की, हालांकि @ प्रोवाइड विधि और फिर विधि के भीतर कई बाइंड बनाने के लिए सीधे बांधने की मशीन का उपयोग किया। गुइंड बाइंडर इंजेक्ट नहीं करेगा।

उत्तर

8

याद रखें कि सभी configure तरीकों में से एक Injectorकिसी भी पहले इंजेक्शन भी हो सकता है में बाइंडिंग के सभी कॉन्फ़िगर करें। जिसके अनुसार, कुछ बातें:

  1. बाध्यकारी एक भी Properties उदाहरण की सामग्री के @Named गुण तो उपयोगी है, वहाँ एक Names.bindProperties(...) विधि है कि यह आप के लिए स्वचालित रूप से करता है। एकमात्र चाल यह है कि आपको उदाहरण configure() पर चलने की आवश्यकता है।

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

  2. प्रदाता विभिन्न उदाहरण वापस कर सकते हैं, और आमतौर पर करते हैं - लेकिन आप सही हैं कि यह आपको कुंजी के बीच अंतर करने में मदद नहीं करेगा। तो सीधे गुण उदाहरण इंजेक्शन भी बदसूरत है, बजाय एक हल्के कारखाना बनाने पर विचार:

    public class ConfigOracle { 
        @Inject private Properties properties; 
    
        public String getAsString(String key) { ... } 
        public int getAsInt(String key) { ... } 
    } 
    
    public class SomeConfigUser { 
        @Inject private ConfigOracle configOracle; 
    
        public void doStuff() { 
        doStuffBasedOn(configOracle.getAsString("my.properties.key")); 
        } 
    } 
    
  3. आप एक Binder एक मॉड्यूल में (या कुछ और) इंजेक्षन करने की जरूरत कभी नहीं करना चाहिए।

    • आप Module लागू करते हैं तो binderconfigure() की एक पैरामीटर हो जाएगा। यदि आप AbstractModule को विस्तारित करना चाहते हैं, तो बस binder() विधि पर कॉल करें।
    • यदि आवश्यक हो, तो आप मॉड्यूल के लिए कन्स्ट्रक्टर तर्कों के माध्यम से निर्भरताओं में गुजर सकते हैं, जहां तक ​​(जहां तक ​​मेरा संबंध है) एकमात्र तरीका है मॉड्यूल को उनके द्वारा बनाई गई बाइंडिंग को अलग करना चाहिए।
    • कोई कारण नहीं है कि आप इंजेक्टर के माध्यम से मॉड्यूल नहीं बना सकते हैं, लेकिन आपको पहले इंजेक्टर रखना होगा, और ऐसा लगता है कि आप केवल एक होने के साथ दूर जाने की कोशिश कर रहे हैं।
    • आप इंजेक्टर से अन्य मामलों की जरूरत है तुम हमेशा @Inject क्षेत्रों/तरीकों/कंस्ट्रक्टर्स के साथ एक Provider कार्यान्वयन लिख सकते हैं, या यहां तक ​​कि एक @Provides विधि में पैरामीटर में (जो filled in with dependencies automatically हो जाएगा)।

कुल मिलाकर मैं अभी भी बच्चे को इंजेक्टर दृष्टिकोण (लिंक और मेरे पिछले जवाब देने के लिए प्रशंसा के लिए धन्यवाद!) है, जो अपने "गतिशील एक इंजेक्शन उदाहरण के आधार पर बाइंडिंग" वर्णन सबसे अच्छा फिट बैठता है के पक्ष में है, और सचमुच होगा यह आसान हो:

class PropertiesModule extends AbstractModule { 
    Properties properties; 

    PropertiesModule(Properties properties) { 
    this.properties = properties; 
    } 

    @Override public void configure() { 
    Names.bindProperties(binder(), properties); 
    } 
} 

Injector oldInjector = Guice.createInjector(allYourOtherModules); 
Module myModule = new PropertiesModule(oldInjector.get(Properties.class)); 
Injector injector = oldInjector.createChildInjector(myModule); 
+0

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

संबंधित मुद्दे

 संबंधित मुद्दे