2013-07-10 8 views
11

मान लीजिए आप एक इंटरफेसस्प्रिंग Autowire एनोटेशन

public interface A { 
    public void doSomething(); 
} 

और दो कार्यान्वयन कक्षाएं

@Component(value="aImpl1") 
public class AImpl1 implements A { 

} 

@Component(value="aImpl2") 
public class AImpl2 implements A{ 

} 

और अंत में एक वर्ग है कि एक 'ए' कार्यान्वयन का उपयोग करेगा:

@Component 
public class MyClass { 
    @Autowire 
    A a; 
} 

अब अगर मैं इंजेक्ट करना चाहता हूं AIMpl1 मैं @Qualifier ("aImpl1") जबकि मैं @Qualifier जोड़ने अगर मैं AImpl2 इंजेक्षन करना चाहते हैं ("aImpl2") जोड़

सवाल यह है: यह संभव वसंत किसी भी तरह का निर्देश देने की है इस मामले में "ए" के सभी कार्यान्वयन को देखने के लिए AImpl1 और AImpl2 और सबसे उपयुक्त कार्यान्वयन का चयन करने के लिए कुछ एप्लिकेशन विशिष्ट सम्मेलनों का उपयोग करें? उदाहरण के लिए इस मामले में मेरा सम्मेलन सबसे बड़ा प्रत्यय (यानी एआईएमपीएल 2) के साथ कार्यान्वयन का उपयोग कर सकता है?

संपादित करें: क्लास MyClass को कार्यान्वयन लुकअप तर्क के बारे में बिल्कुल पता नहीं होना चाहिए, इसे केवल एआईएमपी 2 के ऑब्जेक्ट के साथ अपनी संपत्ति "ए" सेट मिलनी चाहिए।

+0

कहाँ देखने तर्क रखने के लिए करना चाहते हैं? यदि एक्सएमएल संदर्भ कॉन्फ़िगरेशन फ़ाइल में, एक विकल्प उपनाम हैं? कस्टम क्वालीफायर के बारे में क्या? –

+0

आपको क्या लगता है कि उत्तर अद्यतित नहीं है? क्या हाल के वसंत संस्करण में समस्याएं हैं? या यह विशिष्ट अनुप्रयोग संदर्भ वर्ग के साथ काम नहीं करता है? –

+0

@AdrianBer तर्क स्प्रिंग के लिए कुछ प्रकार की कॉन्फ़िगरेशन होना चाहिए और सभी लुकअप पर लागू होना चाहिए। गर्गक ने मुझे जो जवाब दिया था उसका उत्तर दिया। –

उत्तर

5

मान लीजिए कि आपके पास पहले से ही सैकड़ों इंटरफेस और कार्यान्वयन हैं (जैसा कि आपने एक टिप्पणी में कहा था), और आप सभी कोड को दोबारा नहीं बदलना चाहते हैं ... तो यह एक मुश्किल समस्या है ... और यह एक मुश्किल समाधान है:

आप एक कस्टम BeanDefinitionRegistryPostProcessor बना सकते हैं और विधि postProcessBeanDefinitionRegistry या postProcessBeanFactory लागू कर सकते हैं।

इस तरह आपके पास तत्काल और इंजेक्शन से पहले सभी बीन परिभाषाओं तक पहुंच है। अपने तर्कों को जानने के लिए अपना तर्क दें कि आपके प्रत्येक इंटरफेस के लिए पसंदीदा कार्यान्वयन कौन सा है, और उसके बाद, इसे प्राथमिक पर सेट करें।

@Component 
public class CustomBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor { 

    @Override 
    public void postProcessBeanDefinitionRegistry(
      BeanDefinitionRegistry registry) throws BeansException { 

      // this method can be used to set a primary bean, although 
      // beans defined in a @Configuration class will not be avalable here. 

    } 

    @Override 
    public void postProcessBeanFactory(
      ConfigurableListableBeanFactory beanFactory) throws BeansException {  

     // here, all beans are available including those defined by @configuration, @component, xml, etc. 

     // do some magic to somehow find which is the preferred bean name for each interface 
     // you have access to all bean-definition names with: beanFactory.getBeanDefinitionNames() 
     String beanName = "aImpl2"; // let's say is this one 

     // get the definition for that bean and set it as primary 
     beanFactory.getBeanDefinition(beanName).setPrimary(true) 

    } 



} 

कठिन हिस्सा बीन नाम ढूंढना है, यह आपके आवेदन के विनिर्देशों पर निर्भर करता है। मुझे लगता है कि एक सतत नामकरण सम्मेलन होने में मदद मिलेगी।

अद्यतन:

ऐसा लगता है कि इंटरफेस BeanDefinitionRegistryPostProcessor में दोनों तरीकों इस उद्देश्य के लिए इस्तेमाल किया जा सकता। ध्यान में रखते हुए कि postProcessBeanDefinitionRegistry चरण में, @ कॉन्फ़िगरेशन कक्षाओं के माध्यम से कॉन्फ़िगर किया गया बीन्स अभी तक उपलब्ध नहीं है, जैसा कि नीचे दी गई टिप्पणियों में उल्लेख किया गया है।

दूसरी ओर वे वास्तव में postProcessBeanFactory में उपलब्ध हैं।

+1

+1 मैं इन पंक्तियों के साथ कुछ सोच रहा था। बस सोचा कि मैं जोड़ूंगा कि यह दृष्टिकोण शुद्ध '@ कॉन्फ़िगरेशन' आधारित परियोजनाओं के लिए काम नहीं करेगा - यानी ऐसी परियोजनाएं जो xml कॉन्फ़िगरेशन का उपयोग नहीं करती हैं। – Jonathan

+0

बिल्कुल वही जो मैं खोज रहा था! –

+2

@ जोनाथन, आप सही हैं ... बीनडिफिनिशन रजिस्ट्री में @ कॉन्फ़िगरेशन क्लास में परिभाषित बीन्स शामिल नहीं हैं (हालांकि इसमें @ कॉम्पोनेंट, @ सेवा, इत्यादि एनोटेटेड बीन्स शामिल हैं)। लेकिन वे अन्य विधि में उपलब्ध हैं: 'PostProcessBeanFactory', 'ConfigurableListableBeanFactory' के माध्यम से। मैंने अभी एक त्वरित परीक्षण किया है और यह काम करता है। मैं इसे उत्तर में जोड़ दूंगा। – gargc

10

आप List के रूप में सभी implentations इंजेक्षन कर सकते हैं:

@Autowired 
List<A> as; 

या कुंजी के रूप में सेम नाम के साथ Map के रूप में:

@Autowired 
Map<String, A> as; 

और फिर मैन्युअल रूप से उचित कार्यान्वयन चुनें (शायद, एक सेटर विधि में):

@Autowired 
public void setAs(Map<String, A> as) { 
    this.a = ...; 
} 
+0

उत्तर के लिए धन्यवाद लेकिन मैं संरचना वर्ग MyClass को संशोधित नहीं करना चाहता हूं। इसमें एक और एक ही संपत्ति होनी चाहिए (ए); –

2

यदि आपके पास कॉन्फ़िगरर है आयन वर्ग आप ए के कार्यान्वयन के निर्णय के लिए एक विधि का उपयोग कर सकते हैं। फिर स्वत: निकाला उस वर्ग के लिए उपयुक्त उदाहरण इंजेक्ट करेगा।

@Configuration 
public class ApplicationConfiguration { 

    @Bean 
    A getA() { 
     // instantiate the implementation of A that you would like to have injected 
     // or you could use reflection to find the correct class from the classpath. 
     // return the instance 
    } 
} 

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

+0

हां धारणा हमेशा हर जगह एक ही कार्यान्वयन का उपयोग करना है। समस्या यह है कि मेरे पास "ए" जैसे सैकड़ों इंटरफेस हो सकते हैं और मैं प्रत्येक इंटरफ़ेस के लिए कोई विधि नहीं बनाना चाहता हूं। तो मुझे वास्तव में क्या चाहिए @Autowire एनोटेशन के व्यवहार को अनुकूलित करने और इसे तर्क देने के लिए निर्देश देने का एक तरीका है। –

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