एक ही इंटरफ़ेस को लागू करने वाले दो बीन्स को स्वतः-लोड करना - ऑटोवेयर के लिए डिफ़ॉल्ट बीन कैसे सेट करें?


138

पृष्ठभूमि:

मेरे पास स्प्रिंग 2.5 / Java / Tomcat एप्लिकेशन है। निम्नलिखित बीन है, जिसका उपयोग कई स्थानों पर पूरे अनुप्रयोग में किया जाता है

public class HibernateDeviceDao implements DeviceDao

और निम्नलिखित बीन जो नई है:

public class JdbcDeviceDao implements DeviceDao

पहला बीन कॉन्फ़िगर किया गया है (पैकेज में सभी सेम शामिल हैं)

<context:component-scan base-package="com.initech.service.dao.hibernate" />

दूसरा (नया) बीन अलग से कॉन्फ़िगर किया गया है

<bean id="jdbcDeviceDao" class="com.initech.service.dao.jdbc.JdbcDeviceDao">
    <property name="dataSource" ref="jdbcDataSource">
</bean>

सर्वर शुरू करते समय यह (निश्चित रूप से) एक अपवाद होता है:

नेस्टेड अपवाद है org.springframework.beans.factory.NoSuchBeanDefinitionException: कोई अद्वितीय बीन प्रकार का नहीं [com.sevenp.mobile.samplemgmt.service.dk.DeviceDao] परिभाषित किया गया है: अपेक्षित एकल मिलान बीन लेकिन पाया 2: [deviceDao, jdbevice

एक वर्ग से सेम को इस तरह से दबाने की कोशिश कर रहा है

@Autowired
private DeviceDao hibernateDevicDao;

क्योंकि एक ही इंटरफ़ेस को लागू करने में दो सेम हैं।

प्रश्न:

क्या फलियों को कॉन्फ़िगर करना संभव है ताकि

1. मुझे मौजूदा कक्षाओं में परिवर्तन करने की आवश्यकता नहीं है, जो पहले से ही HibernateDeviceDaoस्वत: प्राप्त है

2. अभी भी इस तरह से दूसरी (नई) बीन का उपयोग करने में सक्षम है:

@Autowired
@Qualifier("jdbcDeviceDao")

यानी मुझे HibernateDeviceDaoबीन को कॉन्फ़िगर करने के लिए डिफ़ॉल्ट बीन के रूप में कॉन्फ़िगर करने का एक तरीका चाहिए, JdbcDeviceDaoसाथ ही @Qualifierएनोटेशन के साथ स्पष्ट रूप से निर्दिष्ट करते समय ए के उपयोग की अनुमति देता है ।

मैंने पहले ही कोशिश की है:

मैंने संपत्ति स्थापित करने की कोशिश की

autowire-candidate="false"

JdbcDeviceDao के लिए सेम विन्यास में:

<bean id="jdbcDeviceDao" class="com.initech.service.dao.jdbc.JdbcDeviceDao" autowire-candidate="false">
    <property name="dataSource" ref="jdbcDataSource"/>
</bean>

क्योंकि स्प्रिंग प्रलेखन का कहना है कि

यह इंगित करता है कि इस बीन पर विचार किया जाना चाहिए या नहीं, जब किसी अन्य सेम की ऑटोवायरिंग आवश्यकताओं को पूरा करने के लिए मिलान वाले उम्मीदवारों की तलाश की जाए। ध्यान दें कि यह नाम से स्पष्ट संदर्भों को प्रभावित नहीं करता है, जो निर्दिष्ट बीन को एक ऑटोवेयर उम्मीदवार के रूप में चिह्नित नहीं होने पर भी हल हो जाएगा। *

जिसका अर्थ है कि मैं एनोटेशन JdbcDeviceDaoका उपयोग करके अभी भी ऑटोवेयर कर सकता हूं @Qualifierऔर HibernateDeviceDaoडिफ़ॉल्ट बीन है। जाहिरा तौर पर मेरी व्याख्या सही नहीं थी, हालांकि, सर्वर शुरू करते समय निम्न त्रुटि संदेश में यह परिणाम है:

टाइप की असंतुष्ट निर्भरता [वर्ग com.sevenp.mobile.samplemgmt.service.dao.jdbc.JdbcDeviceDao]: कम से कम 1 मिलान करने की उम्मीद सेम

जिस वर्ग से मैंने क्वालीफ़ायर के साथ बीन को स्वत: प्राप्त करने की कोशिश की है:

@Autowired
@Qualifier("jdbcDeviceDao")

उपाय:

@Resource एनोटेशन का प्रयास करने के लिए स्कैफ़मैन का सुझाव । इसलिए कॉन्फ़िगरेशन में ऑटोवेयर-उम्मीदवार को jdbcDeviceDao के लिए गलत सेट किया गया है और jdbcDeviceDao का उपयोग करते समय मैं इसे @Resource एनोटेशन (@Qualifier के बजाय) का उपयोग करके संदर्भित करता हूं:

@Resource(name = "jdbcDeviceDao")
private JdbcDeviceListItemDao jdbcDeviceDao;

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

जवाबों:


134

मैं हाइबरनेट DAO वर्ग को चिह्नित करने का सुझाव दूंगा @Primary, अर्थात (आपके द्वारा उपयोग किया @Repositoryगया HibernateDeviceDao):

@Primary
@Repository
public class HibernateDeviceDao implements DeviceDao

इस तरह इसे डिफ़ॉल्ट ऑटोवेयर कैंडीडेट के रूप में चुना जाएगा, जिसकी आवश्यकता autowire-candidateअन्य सेम पर नहीं होगी ।

इसके अलावा, उपयोग करने के बजाय @Autowired @Qualifier, मुझे @Resourceविशिष्ट बीन्स चुनने के लिए उपयोग करने में अधिक सुरुचिपूर्ण लगता है , अर्थात

@Resource(name="jdbcDeviceDao")
DeviceDao deviceDao;

मैं इस सवाल का उल्लेख करना भूल गया कि मैं स्प्रिंग 2.5 का उपयोग कर रहा हूं (मैंने अब प्रश्न संपादित कर दिया है) इसलिए @Primary कोई विकल्प नहीं है।
सिमोन

1
@ साइमन: हाँ, यह महत्वपूर्ण नहीं था। @Resourceएनोटेशन का प्रयास करें , जैसा कि मैंने भी सुझाव दिया था।
स्कैफ़मैन

1
धन्यवाद, संसाधन एनोटेशन ने समस्या को हल कर दिया - अब ऑटोवेयर-उम्मीदवार संपत्ति काम करती है जैसा कि मुझे उम्मीद थी।
सिमोन

धन्यवाद! के माध्यम से सेम का नाम निर्दिष्ट करने में क्या अंतर है @Resourceऔर @Qualifierअलग तथ्य यह है कि पूर्व उत्तरार्द्ध की तुलना में अपेक्षाकृत नया है से,?
asgs

1
@asgs संसाधन एनोटेशन का उपयोग करना चीजों को सरल बनाता है। स्वत: प्राप्त / क्वालीफ़ायर कॉम्बो होने के बजाय, आप इसे निर्भरता इंजेक्शन के लिए चिह्नित कर सकते हैं और एक पंक्ति में नाम निर्दिष्ट कर सकते हैं। ध्यान दें कि सिमोन का समाधान निरर्थक है, स्वत: संलग्न एनोटेशन को हटाया जा सकता है।
गिल्बर्ट एरेनास डैगर

37

व्हाट अबाउट @Primary ?

इंगित करता है कि एक सेम को वरीयता दी जानी चाहिए जब कई उम्मीदवार एकल-मूल्यवान निर्भरता को स्वीकार करने के लिए योग्य हैं । यदि उम्मीदवारों के बीच वास्तव में एक 'प्राथमिक' बीन मौजूद है, तो यह स्वतः प्राप्त मूल्य होगा। यह एनोटेशन वसंत एक्सएमएल में <bean>तत्व की primaryविशेषता के बराबर शब्दार्थ है ।

@Primary
public class HibernateDeviceDao implements DeviceDao

या यदि आप चाहते हैं कि आपका Jdbc संस्करण डिफ़ॉल्ट रूप से उपयोग किया जाए:

<bean id="jdbcDeviceDao" primary="true" class="com.initech.service.dao.jdbc.JdbcDeviceDao">

@Primary एकीकरण परीक्षण के लिए भी बहुत अच्छा है जब आप इसे तोड़कर उत्पादन बीन को आसानी से स्टड संस्करण के साथ बदल सकते हैं।


मैं इस सवाल का उल्लेख करना भूल गया कि मैं स्प्रिंग 2.5 का उपयोग कर रहा हूं (मैंने अब प्रश्न संपादित कर दिया है) इसलिए @Primary कोई विकल्प नहीं है।
सिमोन

1
@ साइमन: मेरा मानना ​​है कि primary=""विशेषता पहले उपलब्ध थी। बस HibernateDeviceDaoXML में घोषित करें और इसे घटक / एनोटेशन स्कैनिंग से बाहर रखें।
टॉमाज़ नर्कविक्ज़

1
दस्तावेज़ के अनुसार यह 3.0 के बाद से उपलब्ध है: static.springsource.org/spring/docs/3.1.x/javadoc-api/org/… अच्छा टिप किसी भी तरह, मैं अगले प्रोजेक्ट के लिए प्राथमिक एनोटेशन याद रखूँगा जो मैं सक्षम हूँ का उपयोग करने के लिए स्प्रिंग 3.x
सिमोन

8

स्प्रिंग 2.5 के लिए, नहीं @Primary। उपयोग करने का एकमात्र तरीका है @Qualifier


2
The use of @Qualifier will solve the issue.
Explained as below example : 
public interface PersonType {} // MasterInterface

@Component(value="1.2") 
public class Person implements  PersonType { //Bean implementing the interface
@Qualifier("1.2")
    public void setPerson(PersonType person) {
        this.person = person;
    }
}

@Component(value="1.5")
public class NewPerson implements  PersonType { 
@Qualifier("1.5")
    public void setNewPerson(PersonType newPerson) {
        this.newPerson = newPerson;
    }
}

Now get the application context object in any component class :

Object obj= BeanFactoryAnnotationUtils.qualifiedBeanOfType((ctx).getAutowireCapableBeanFactory(), PersonType.class, type);//type is the qualifier id

you can the object of class of which qualifier id is passed.

0

कारण @Resource (नाम = "{आपका बच्चा वर्ग नाम}") काम करता है, लेकिन @Autowired कभी-कभी काम नहीं करता क्योंकि उनके मिलान अनुक्रम के अंतर के कारण होता है

@Autowire
प्रकार, क्वालिफायर, नाम का मिलान क्रम

@Resource
नाम, प्रकार, क्वालिफायर के मिलान क्रम

अधिक विवरण स्पष्टीकरण यहां पाया जा सकता है:
इंजेक्शन और संसाधन और ऑटोवॉइड एनोटेशन

इस मामले में, माता-पिता वर्ग या इंटरफ़ेस से विरासत में मिली विभिन्न बाल वर्ग @Autowire को भ्रमित करते हैं, क्योंकि वे एक ही प्रकार के होते हैं; जैसा कि @Resource पहले मिलान प्राथमिकता के रूप में नाम का उपयोग करता है, यह काम करता है।

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