खोज…


एक विशिष्ट प्रकार की सभी फलियों को स्वतः प्राप्त करना

यदि आपको एक ही इंटरफ़ेस के कई कार्यान्वयन मिल गए हैं, तो स्प्रिंग उन सभी को एक संग्रह वस्तु में स्वाहा कर सकता है। मैं एक उदाहरण का उपयोग करने के लिए जा रहा हूँ एक Validator पैटर्न 1

फू कक्षा:

public class Foo {
     private String name;
     private String emailAddress;
     private String errorMessage;
     /** Getters & Setters omitted **/
}

इंटरफेस:

public interface FooValidator {
    public Foo validate(Foo foo);
}

नाम मान्यकर्ता वर्ग:

@Component(value="FooNameValidator")
public class FooNameValidator implements FooValidator {
    @Override
    public Foo validate(Foo foo) {
        //Validation logic goes here.
    }
}

ईमेल सत्यापनकर्ता वर्ग:

@Component(value="FooEmailValidator")
public class FooEmailValidator implements FooValidator {
    @Override
    public Foo validate(Foo foo) {
        //Different validation logic goes here.
    }
}

अब आप इन सत्यापनकर्ताओं को व्यक्तिगत रूप से या एक कक्षा में एक साथ स्वायत्त कर सकते हैं।

इंटरफेस:

public interface FooService {
    public void handleFoo(Foo foo);
}

वर्ग:

@Service
public class FooServiceImpl implements FooService {
    /** Autowire all classes implementing FooValidator interface**/
    @Autowired
    private List<FooValidator> allValidators;

    @Override
    public void handleFoo(Foo foo) {
       /**You can use all instances from the list**/
       for(FooValidator validator : allValidators) {
           foo = validator.validate(foo);               
       }
    }   
}

यह ध्यान देने योग्य है कि यदि आपके पास स्प्रिंग IoC कंटेनर में इंटरफ़ेस का एक से अधिक कार्यान्वयन है और निर्दिष्ट नहीं करें कि आप @Qualifier एनोटेशन के साथ @Qualifier उपयोग करना चाहते हैं, तो स्प्रिंग प्रारंभ करने का प्रयास करते समय एक अपवाद फेंक देगा, क्योंकि यह जीता था ' टी पता है कि किसका उपयोग करना है।

1: इस तरह के सरल सत्यापन करने का यह सही तरीका नहीं है। यह ऑटोवायरिंग के बारे में एक सरल उदाहरण है। यदि आप एक बहुत आसान सत्यापन विधि का विचार चाहते हैं, तो देखें कि स्प्रिंग एनोटेशन के साथ सत्यापन कैसे करता है।

बीन की घोषणा

एक सेम की घोषणा करने के लिए बस के साथ एक विधि व्याख्या @Bean एनोटेशन या के साथ एक कक्षा व्याख्या @Component एनोटेशन (एनोटेशन @Service , @Repository , @Controller रूप में अच्छी तरह से इस्तेमाल किया जा सकता है)।

जब JavaConfig इस तरह की विधि का सामना करता है, तो यह उस पद्धति को निष्पादित करेगा और बीनफैक्टरी के भीतर एक बीन के रूप में रिटर्न वैल्यू को पंजीकृत करेगा। डिफ़ॉल्ट रूप से, बीन नाम विधि नाम का होगा।

हम तीन तरीकों में से एक का उपयोग करके बीन बना सकते हैं:

  1. जावा आधारित कॉन्फ़िगरेशन का उपयोग करना : कॉन्फ़िगरेशन फ़ाइल में हमें @bean एनोटेशन का उपयोग करके बीन घोषित करने की आवश्यकता होती है

    @Configuration
    public class AppConfig {
        @Bean
        public TransferService transferService() {
            return new TransferServiceImpl();
        }
    }
    
  2. XML आधारित कॉन्फ़िगरेशन का उपयोग करना : XML आधारित कॉन्फ़िगरेशन के लिए हमें एप्लिकेशन कॉन्फ़िगरेशन XML में घोषणात्मक बीन बनाने की आवश्यकता है

     <beans>
         <bean name="transferService" class="com.acme.TransferServiceImpl"/>
     </beans>
    
  3. एनोटेशन-चालित घटक : एनोटेशन-चालित घटकों के लिए, हमें उस श्रेणी में @Component एनोटेशन जोड़ना होगा जिसे हम बीन घोषित करना चाहते हैं।

     @Component("transferService")
     public class TransferServiceImpl implements TransferService {
         ...
     }
    

अब नाम transferService साथ सभी तीन फलियां BeanFactory या ApplicationContext में उपलब्ध हैं।

बेसिक एनोटेशन ऑटोवेयरिंग

इंटरफेस:

public interface FooService {
    public int doSomething();
}

वर्ग:

@Service
public class FooServiceImpl implements FooService {
    @Override
    public int doSomething() {
        //Do some stuff here
        return 0;
    }
}

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

आप किसी भी वर्ग में इस सेम तक पहुंच प्राप्त कर सकते हैं जो @Autowired एनोटेशन का उपयोग करके स्प्रिंग @Autowired कंटेनर द्वारा @Autowired

उपयोग:

@Autowired([required=true])

@Autowired एनोटेशन पहले टाइप करके ऑटोवेयर करने का प्रयास करेगा, और फिर अस्पष्टता की स्थिति में बीन नाम पर वापस आ जाएगा।

इस एनोटेशन को कई अलग-अलग तरीकों से लागू किया जा सकता है।

कंस्ट्रक्टर इंजेक्शन:

public class BarClass() {
    private FooService fooService         

    @Autowired
    public BarClass(FooService fooService) {
        this.fooService = fooService;
    }
}

फ़ील्ड इंजेक्शन:

public class BarClass() {
    @Autowired
    private FooService fooService;
}

सेटर इंजेक्शन:

public class BarClass() {
    private FooService fooService;

    @Autowired
    public void setFooService(FooService fooService) {
        this.fooService = fooService;
    }
}

गतिशील बीन तात्कालिकता के लिए FactoryBean का उपयोग करना

सेम को इंजेक्ट करने के लिए गतिशील रूप से निर्णय लेने के लिए, हम FactoryBean s का उपयोग कर सकते हैं। ये वे वर्ग हैं जो कारखाने विधि पैटर्न को लागू करते हैं, कंटेनर के लिए सेम के उदाहरण प्रदान करते हैं। वे वसंत द्वारा पहचाने जाते हैं और पारदर्शी रूप से उपयोग किए जा सकते हैं, यह जानने की आवश्यकता के बिना कि बीन एक कारखाने से आता है। उदाहरण के लिए:

public class ExampleFactoryBean extends AbstractFactoryBean<String> {
    // This method determines the type of the bean for autowiring purposes
    @Override
    public Class<?> getObjectType() {
        return String.class;
    }

    // this factory method produces the actual bean
    @Override
    protected String createInstance() throws Exception {
        // The thing you return can be defined dynamically,
        // that is read from a file, database, network or just
        // simply randomly generated if you wish.
        return "Something from factory";
    }
}

विन्यास:

@Configuration
public class ExampleConfig {
    @Bean
    public FactoryBean<String> fromFactory() {
        return new ExampleFactoryBean();
    }
}

सेम हो रही है:

AbstractApplicationContext context = new AnnotationConfigApplicationContext(ExampleConfig.class);
String exampleString = (String) context.getBean("fromFactory");

वास्तविक FactoryBean प्राप्त करने के लिए, सेम के नाम से पहले एम्परसेंड उपसर्ग का उपयोग करें:

FactoryBean<String> bean = (FactoryBean<String>) context.getBean("&fromFactory");

कृपया ध्यान दें कि आप केवल prototype या singleton स्कोप का उपयोग कर सकते हैं - prototype ओवरराइड के दायरे को बदलने के लिए isSingleton विधि:

public class ExampleFactoryBean extends AbstractFactoryBean<String> {
    @Override
    public boolean isSingleton() {
        return false;
    }

    // other methods omitted for readability reasons
}

ध्यान दें कि स्कूपिंग से तात्पर्य वास्तविक निर्माण से है, न कि कारखाने के बीन से।

प्रोटोटाइप-स्कोप बीन्स को सिंग्लेटन्स में इंजेक्ट करें

कंटेनर एक एकल बीन बनाता है और केवल एक बार में सहयोगियों को इंजेक्ट करता है। यह वांछित व्यवहार नहीं है जब एक सिंगलटन बीन में एक प्रोटोटाइप-स्कॉप्ड सहयोगी होता है, क्योंकि प्रोटोटाइप-स्कोपेड बीन को हर बार एक्सेसरी के माध्यम से एक्सेस किया जा रहा होना चाहिए।

इस समस्या के कई समाधान हैं:

  1. लुकअप मेथड इंजेक्शन का प्रयोग करें
  2. javax.inject.Provider माध्यम से एक प्रोटोटाइप-स्कोप बीन को javax.inject.Provider
  3. org.springframework.beans.factory.ObjectFactory (# 2 के एक बराबर है, लेकिन उस वर्ग के साथ जो वसंत के लिए विशिष्ट है) के माध्यम से एक प्रोटोटाइप-स्कॉप्ड बीन को पुनः प्राप्त करें।
  4. ApplicationContextAware इंटरफ़ेस को लागू करने के माध्यम से एक सिंगलटन बीन कंटेनर को जागरूक करें

दृष्टिकोण # 3 और # 4 आमतौर पर हतोत्साहित किए जाते हैं, क्योंकि वे ऐप को स्प्रिंग फ्रेमवर्क में मजबूती से बाँधते हैं। इस प्रकार, वे इस उदाहरण में शामिल नहीं हैं।

XML कॉन्फ़िगरेशन और एक अमूर्त विधि के माध्यम से लुकअप विधि इंजेक्शन

जावा क्लासेस

public class Window {
}

public abstract class WindowGenerator {

    public Window generateWindow() {
        Window window = createNewWindow(); // new instance for each call
        ... 
    }

    protected abstract Window createNewWindow(); // lookup method
}

एक्सएमएल

<bean id="window" class="somepackage.Window" scope="prototype" lazy-init="true"/>

<bean id="windowGenerator" class="somepackage.WindowGenerator">
    <lookup-method name="createNewWindow" bean="window"/>
</bean>

जावा कॉन्फ़िगरेशन और @Component के माध्यम से लुकअप विधि इंजेक्शन

जावा क्लासेस

public class Window {
}

@Component
public class WindowGenerator {

    public Window generateWindow() {
        Window window = createNewWindow(); // new instance for each call
        ...
    }

    @Lookup
    protected Window createNewWindow() {
        throw new UnsupportedOperationException();
    }
}

जावा कॉन्फ़िगरेशन

@Configuration
@ComponentScan("somepackage") // package where WindowGenerator is located
public class MyConfiguration {

    @Bean
    @Lazy
    @Scope(scopeName = ConfigurableBeanFactory.SCOPE_PROTOTYPE)
    public Window window() {
        return new Window();
    }
}

जावा कॉन्फ़िगरेशन के माध्यम से मैनुअल लुकअप विधि इंजेक्शन

जावा क्लासेस

public class Window {
}

public abstract class WindowGenerator {

    public Window generateWindow() {
        Window window = createNewWindow(); // new instance for each call
        ...
    }

    protected abstract Window createNewWindow(); // lookup method
}

जावा कॉन्फ़िगरेशन

@Configuration
public class MyConfiguration {

    @Bean
    @Lazy
    @Scope(scopeName = ConfigurableBeanFactory.SCOPE_PROTOTYPE)
    public Window window() {
        return new Window();
    }

    @Bean
    public WindowGenerator windowGenerator(){
        return new WindowGenerator() {
            @Override
            protected Window createNewWindow(){
                return window();
            }
        };
    }
}

javax.inject.Provider माध्यम से सिंगलटन में एक javax.inject.Provider बीन का इंजेक्शन

जावा कक्षाएं

public class Window {
}

public class WindowGenerator {

    private final Provider<Window> windowProvider;

    public WindowGenerator(final Provider<Window> windowProvider) {
        this.windowProvider = windowProvider;
    }

    public Window generateWindow() {
        Window window = windowProvider.get(); // new instance for each call   
        ...
    }
}

एक्सएमएल

<bean id="window" class="somepackage.Window" scope="prototype" lazy-init="true"/>

<bean id="windowGenerator" class="somepackage.WindowGenerator">
    <constructor-arg>
        <bean class="org.springframework.beans.factory.config.ProviderCreatingFactoryBean">
            <property name="targetBeanName" value="window"/>
        </bean>
    </constructor-arg>
</bean>

उसी दृष्टिकोण का उपयोग अन्य स्कोप के लिए भी किया जा सकता है (जैसे इंजेक्शन के लिए एक अनुरोध-स्कॉप्ड बीन को सिंगलटन में)।

@Qualifier के साथ विशिष्ट बीन इंस्टेंसेस को ऑटो करना

यदि आपको एक ही इंटरफ़ेस के कई कार्यान्वयन मिले हैं, तो स्प्रिंग को यह जानने की आवश्यकता है कि इसे किस वर्ग में स्वीकार करना चाहिए। मैं इस उदाहरण में एक Validator पैटर्न का उपयोग करने जा रहा हूं। 1

फू कक्षा:

public class Foo {
     private String name;
     private String emailAddress;
     private String errorMessage;
     /** Getters & Setters omitted **/
}

इंटरफेस:

public interface FooValidator {
    public Foo validate(Foo foo);
}

नाम मान्यकर्ता वर्ग:

@Component(value="FooNameValidator")
public class FooNameValidator implements FooValidator {
    @Override
    public Foo validate(Foo foo) {
        //Validation logic goes here.
    }
}

ईमेल सत्यापनकर्ता वर्ग:

@Component(value="FooEmailValidator")
public class FooEmailValidator implements FooValidator {
    @Override
    public Foo validate(Foo foo) {
        //Different validation logic goes here.
    }
}

अब आप इन सत्यापनकर्ताओं को व्यक्तिगत रूप से एक वर्ग में शामिल कर सकते हैं।

इंटरफेस:

public interface FooService {
    public void handleFoo(Foo foo);
}

वर्ग:

@Service
public class FooServiceImpl implements FooService {
    /** Autowire validators individually **/
    @Autowired
    /* 
     * Notice how the String value here matches the value 
     * on the @Component annotation? That's how Spring knows which 
     * instance to autowire.
     */
    @Qualifier("FooNameValidator")
    private FooValidator nameValidator;

    @Autowired
    @Qualifier("FooEmailValidator")
    private FooValidator emailValidator;

    @Override
    public void handleFoo(Foo foo) {
        /**You can use just one instance if you need**/
        foo = nameValidator.validate(foo);
    }   
}

यह ध्यान देने योग्य है कि यदि आपके पास स्प्रिंग IoC कंटेनर में इंटरफ़ेस का एक से अधिक कार्यान्वयन है और निर्दिष्ट नहीं करें कि आप @Qualifier एनोटेशन के साथ @Qualifier उपयोग करना चाहते हैं, तो स्प्रिंग प्रारंभ करने का प्रयास करते समय एक अपवाद फेंक देगा, क्योंकि यह जीता था ' टी पता है कि किसका उपयोग करना है।

1: इस तरह के सरल सत्यापन करने का यह सही तरीका नहीं है। यह ऑटोवायरिंग के बारे में एक सरल उदाहरण है। यदि आप एक बहुत आसान सत्यापन विधि का विचार चाहते हैं, तो देखें कि स्प्रिंग एनोटेशन के साथ सत्यापन कैसे करता है।

सामान्य प्रकार के मापदंडों का उपयोग करते हुए वर्गों के विशिष्ट उदाहरणों को स्वचालित करना

यदि आपको एक सामान्य प्रकार के पैरामीटर के साथ एक इंटरफ़ेस मिला है, तो स्प्रिंग उस का उपयोग केवल ऑटोवेयर कार्यान्वयन के लिए कर सकता है जो आपके द्वारा निर्दिष्ट एक प्रकार के पैरामीटर को लागू करता है।

इंटरफेस:

public interface GenericValidator<T> {
    public T validate(T object);
}

फू सत्यापनकर्ता वर्ग:

@Component
public class FooValidator implements GenericValidator<Foo> {
    @Override
    public Foo validate(Foo foo) {
        //Logic here to validate foo objects.
    }
}

बार मान्य वर्ग:

@Component
public class BarValidator implements GenericValidator<Bar> {
    @Override
    public Bar validate(Bar bar) {
        //Bar validation logic here
    }
}

अब आप इन सत्यापनकर्ताओं को यह निर्धारित करने के लिए टाइप पैरामीटर का उपयोग करके ऑटॉवेयर कर सकते हैं कि किस उदाहरण को ऑटॉयर करना है।

इंटरफेस:

public interface FooService {
    public void handleFoo(Foo foo);
}

वर्ग:

@Service
public class FooServiceImpl implements FooService {
    /** Autowire Foo Validator **/
    @Autowired
    private GenericValidator<Foo> fooValidator;

    @Override
    public void handleFoo(Foo foo) {
        foo = fooValidator.validate(foo);
    }   
}


Modified text is an extract of the original Stack Overflow Documentation
के तहत लाइसेंस प्राप्त है CC BY-SA 3.0
से संबद्ध नहीं है Stack Overflow