ऑटोरायरिंग स्प्रिंग में कैसे काम करता है?


510

मैं थोड़ा उलझन में हूँ कि कैसे नियंत्रण ( IoC) में उलटा काम करता है Spring

मान लीजिए कि मेरे पास एक सेवा वर्ग है जो UserServiceImplकि इम्प्लीमेंट UserServiceइंटरफेस को बुलाता है।

यह कैसे होगा @Autowired?

और मेरे में Controllers, कैसे होगा मैं instantiateएक instanceइस सेवा का?

क्या मैं बस निम्नलिखित करूंगा?

UserService userService = new UserServiceImpl();

जवाबों:


703

सबसे पहले, और सबसे महत्वपूर्ण - सभी स्प्रिंग बीन्स को प्रबंधित किया जाता है - वे एक कंटेनर के अंदर "लाइव" होते हैं, जिसे "एप्लिकेशन संदर्भ" कहा जाता है।

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

ऑटोबायरिंग एक बीन के उदाहरण को दूसरे बीन की आवृत्ति में वांछित क्षेत्र में रखने से होता है। दोनों वर्गों को सेम होना चाहिए, अर्थात उन्हें आवेदन के संदर्भ में रहने के लिए परिभाषित किया जाना चाहिए।

एप्लिकेशन संदर्भ में "जीवित" क्या है? इसका अर्थ है कि संदर्भ वस्तुओं को त्वरित करता है, न कि आप। यानी - आप कभी नहीं बनाते हैं new UserServiceImpl()- कंटेनर प्रत्येक इंजेक्शन बिंदु पाता है और वहां एक उदाहरण सेट करता है।

आपके नियंत्रकों में, आपके पास बस निम्नलिखित हैं:

@Controller // Defines that this class is a spring bean
@RequestMapping("/users")
public class SomeController {

    // Tells the application context to inject an instance of UserService here
    @Autowired
    private UserService userService;

    @RequestMapping("/login")
    public void login(@RequestParam("username") String username,
           @RequestParam("password") String password) {

        // The UserServiceImpl is already injected and you can use it
        userService.login(username, password);

    }
}

कुछ नोट:

  • अपने में applicationContext.xmlआप सक्षम होना चाहिए <context:component-scan>ताकि कक्षाओं के लिए जांच की जाती है @Controller, @Serviceआदि एनोटेशन।
  • स्प्रिंग-एमवीसी एप्लिकेशन के लिए प्रवेश बिंदु डिस्पैचरसर्वलेट है, लेकिन यह आपसे छिपा हुआ है, और इसलिए आवेदन के संदर्भ की प्रत्यक्ष बातचीत और बूटस्ट्रैपिंग दृश्य के पीछे होती है।
  • UserServiceImplबीन के रूप में भी परिभाषित किया जाना चाहिए - या तो एनोटेशन <bean id=".." class="..">का उपयोग या उपयोग करना @Service। चूंकि यह एकमात्र कार्यान्वयनकर्ता UserServiceहोगा, इसलिए इसे इंजेक्ट किया जाएगा।
  • @Autowiredएनोटेशन के अलावा , स्प्रिंग XML-configurable ऑटोवेयरिंग का उपयोग कर सकता है। उस स्थिति में सभी फ़ील्ड्स में एक नाम या प्रकार होता है जो मौजूदा बीन के साथ मेल खाता है, स्वचालित रूप से बीन इंजेक्ट हो जाता है। वास्तव में, यह ऑटोवायरिंग का प्रारंभिक विचार था - बिना किसी कॉन्फ़िगरेशन के निर्भरता वाले क्षेत्रों को इंजेक्ट करना। अन्य एनोटेशन चाहते @Inject, @Resourceका भी इस्तेमाल किया जा सकता है।

7
हां, UserServiceImpl को सेवा के साथ एनोटेट किया गया है, और UserService इंटरफ़ेस है
Bozho

16
डिफ़ॉल्ट स्कोप सिंगलटन है, इसलिए आपके पास बीन का केवल एक उदाहरण होगा, जिसे कई स्थानों पर इंजेक्ट किया जाता है। यदि आप स्पष्ट रूप से गुंजाइश को "प्रोटोटाइप" के रूप में परिभाषित करते हैं, तो कई उदाहरण मौजूद होंगे, संभवतः आलसी (कॉन्फ़िगरेशन के आधार पर)
Bozho

2
आपकी पोस्ट के लिए बहुत बहुत धन्यवाद, यह वास्तव में मेरे लिए चीजों को मंजूरी दे दी। 'चूंकि यह एकमात्र कार्यान्वयनकर्ता या उपयोगकर्ता सेवा होगा, इसलिए इसे इंजेक्ट किया जाएगा।' - क्या होगा अगर यूजर्स की सेवा को लागू करने वाले कई वर्ग हैं? स्प्रिंग को कैसे पता चलता है कि उसे किस कार्यान्वयन का उपयोग करना चाहिए?
शशिगामी

7
यदि कोई "प्राथमिक" नामित है, तो वह इसका उपयोग करता है। अन्यथा यह एक अपवाद फेंकता है
Bozho

3
नहीं, userService केवल एक बार बनाया गया है, यह सिंगलटन-स्कोप में है
Bozho

64

इस पर निर्भर करता है कि आप एनोटेशन मार्ग या बीन एक्सएमएल परिभाषा मार्ग चाहते हैं।

कहते हैं कि आप में सेम परिभाषित किया गया था applicationContext.xml:

<beans ...>

    <bean id="userService" class="com.foo.UserServiceImpl"/>

    <bean id="fooController" class="com.foo.FooController"/>

</beans>

जब अनुप्रयोग प्रारंभ होता है, तो स्वतः पूर्ण होता है। इसलिए, fooControllerजो तर्क के लिए UserServiceImpl, वर्ग का उपयोग करना चाहता है , आप इसे निम्नानुसार एनोटेट करेंगे:

public class FooController {

    // You could also annotate the setUserService method instead of this
    @Autowired
    private UserService userService;

    // rest of class goes here
}

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

यदि आप निम्न कार्य करते हैं:

UserService service = new UserServiceImpl();

@Autowiredजब तक आप खुद इसे सेट नहीं करेंगे, यह नहीं उठाएगा ।


2
तो इसमें परिभाषित करने का क्या उपयोग bean idहै applicationContext.xml। हमें userServiceचर को UserServiceप्रकार के साथ परिभाषित करना होगा । तो xmlफाइल में एंट्री क्यों करें ।
वाइपर

20

@Autowired स्प्रिंग 2.5 में पेश किया गया एक एनोटेशन है, और इसका उपयोग केवल इंजेक्शन के लिए किया जाता है।

उदाहरण के लिए:

class A {

    private int id;

    // With setter and getter method
}

class B {

    private String name;

    @Autowired // Here we are injecting instance of Class A into class B so that you can use 'a' for accessing A's instance variables and methods.
    A a;

    // With setter and getter method

    public void showDetail() {
        System.out.println("Value of id form A class" + a.getId(););
    }
}

10
यह संकलन नहीं होगा और आम तौर पर गलत है। @Autowiredइसका मतलब यह नहीं है कि "आप Bकक्षा से सभी फ़ंक्शन (विधि) और कक्षा में चर का उपयोग कर सकते हैं A"। क्या यह करता है का एक उदाहरण पेश करती है Aके उदाहरण में Bहै, तो आप क्या कर सकते हैं a.getId()से B
दिमित्री मिनकोवस्की

@dimadima तो अगर वह System.out.println ("आईडी फॉर्म A क्लास" + a.getId ()) ;, और नहीं करता है, जैसा कि उसने वास्तव में किया है तो यह अधिक सही होगा। कृपया उत्तर दें, क्योंकि यह मेरे लिए सहज रूप से स्पष्ट है और मेरी वर्तमान समझ के अनुसार ऑटोरिंग समझा रहा है।
जॉन डोए


1
जैसा कि मैं इसके लिए नया हूँ, बेहतर समझने के लिए, क्या डिफ़ॉल्ट निर्माणकर्ता का उपयोग करके कक्षा A को तत्काल अनधिकृत किया जाएगा? यदि नहीं, तो मानों को बीन या सेवा में त्वरित रूप से कैसे प्राप्त किया जाए यदि हम स्वत: उपयोग करते हैं। मुझे लगता है कि अगर यह डिफॉल्ट कंस्ट्रक्टर को बुलाता है, तो पहली बार में ऑटोवेयरिंग का उपयोग क्यों करें, बस ए = नया ए () करें। कृपया स्पष्ट करें?
समीर

@ स्वत: निर्भरता के आधार पर आप अपने यूनिट टेस्ट और कंट्रोलर, सर्विस और डाओ क्लासेज में बहुत सारे बॉयलरप्लेट कोड सहेज सकते हैं, क्योंकि खेतों की तात्कालिकता अपने आप आती ​​है। कंस्ट्रक्टर को कॉल करने की आवश्यकता नहीं है।
किल्टेक

9

@Autowiredआंतरिक रूप से कैसे काम करता है ?

उदाहरण:

class EnglishGreeting {
   private Greeting greeting;
   //setter and getter
}

class Greeting {
   private String message;
   //setter and getter
}

.xml फ़ाइल का उपयोग न करने पर यह एक जैसे दिखाई देगा @Autowired:

<bean id="englishGreeting" class="com.bean.EnglishGreeting">
   <property name="greeting" ref="greeting"/>
</bean>

<bean id="greeting" class="com.bean.Greeting">
   <property name="message" value="Hello World"/>
</bean>

यदि आप उपयोग कर रहे हैं @Autowiredतो:

class EnglishGreeting {
   @Autowired //so automatically based on the name it will identify the bean and inject.
   private Greeting greeting;
   //setter and getter
}

.xml फ़ाइल का उपयोग न करने पर यह एक जैसे दिखाई देगा @Autowired:

<bean id="englishGreeting" class="com.bean.EnglishGreeting"></bean>

<bean id="greeting" class="com.bean.Greeting">
   <property name="message" value="Hello World"/>
</bean>

यदि अभी भी कुछ संदेह है तो नीचे लाइव डेमो के माध्यम से जाएं

@Autowired आंतरिक रूप से कैसे काम करता है?


6

आपको बस UserServiceImplएनोटेशन के साथ अपनी सर्विस क्लास को एनोटेट करना होगा :

@Service("userService")

स्प्रिंग कंटेनर इस वर्ग के जीवन चक्र का ध्यान रखेगा क्योंकि यह सेवा के रूप में पंजीकृत है।

फिर अपने कंट्रोलर में आप इसे ऑटो वायर (इंस्टेंट) कर सकते हैं और इसकी कार्यक्षमता का उपयोग कर सकते हैं:

@Autowired
UserService userService;

3

वसंत निर्भरता इंजेक्शन आपको अपनी कक्षाओं से युग्मन हटाने में मदद करता है। इस तरह वस्तु बनाने के बजाय:

UserService userService = new UserServiceImpl();

DI शुरू करने के बाद आप इसका उपयोग करेंगे:

@Autowired
private UserService userService;

इसे प्राप्त करने के लिए आपको अपनी ServiceConfigurationफ़ाइल में अपनी सेवा का बीन बनाने की आवश्यकता है । उसके बाद आपको उस ServiceConfigurationवर्ग को अपनी WebApplicationConfigurationकक्षा में आयात करने की आवश्यकता है ताकि आप उस बीन को अपने नियंत्रक को इस तरह स्वाहा कर सकें:

public class AccController {

    @Autowired
    private UserService userService;
} 

आप एक जावा विन्यास आधारित POC यहां पा सकते हैं उदाहरण


1

मानक तरीका:

@RestController
public class Main {
    UserService userService;

    public Main(){
        userService = new UserServiceImpl();
    }

    @GetMapping("/")
    public String index(){
        return userService.print("Example test");
    }
}

उपयोगकर्ता सेवा इंटरफ़ेस:

public interface UserService {
    String print(String text);
}

UserServiceImpl वर्ग:

public class UserServiceImpl implements UserService {
    @Override
    public String print(String text) {
        return text + " UserServiceImpl";
    }
}

आउटपुट: Example test UserServiceImpl

यह तंग युग्मित वर्गों, खराब डिजाइन उदाहरण का एक शानदार उदाहरण है और परीक्षण के साथ समस्या होगी (पावरमॉकिटो भी खराब है)।

अब स्प्रिंगबूट निर्भरता इंजेक्शन पर एक नज़र डालते हैं, ढीले युग्मन का अच्छा उदाहरण:

इंटरफ़ेस ही रहता है,

मुख्य वर्ग:

@RestController
public class Main {
    UserService userService;

    @Autowired
    public Main(UserService userService){
        this.userService = userService;
    }

    @GetMapping("/")
    public String index(){
        return userService.print("Example test");
    }
}

ServiceUserImpl वर्ग:

@Component
public class UserServiceImpl implements UserService {
    @Override
    public String print(String text) {
        return text + " UserServiceImpl";
    }
}

आउटपुट: Example test UserServiceImpl

और अब परीक्षण लिखना आसान है:

@RunWith(MockitoJUnitRunner.class)
public class MainTest {
    @Mock
    UserService userService;

    @Test
    public void indexTest() {
        when(userService.print("Example test")).thenReturn("Example test UserServiceImpl");

        String result = new Main(userService).index();

        assertEquals(result, "Example test UserServiceImpl");
    }
}

मैंने @Autowiredनिर्माणकर्ता पर एनोटेशन दिखाया, लेकिन इसे सेटर या फ़ील्ड पर भी उपयोग किया जा सकता है।


0

नियंत्रण के व्युत्क्रम की पूरी अवधारणा का मतलब है कि आप एक अव्यवस्था से वस्तुओं को मैन्युअल रूप से मुक्त करने के लिए स्वतंत्र हैं और सभी आवश्यक निर्भरताएं प्रदान करते हैं। जब आप उपयुक्त एनोटेशन (जैसे @Service) वर्ग के साथ वर्ग को एनोटेट करते हैं, तो स्प्रिंग स्वचालित रूप से आपके लिए ऑब्जेक्ट को त्वरित करेगा। यदि आप एनोटेशन से परिचित नहीं हैं, तो आप इसके बजाय XML फ़ाइल का भी उपयोग कर सकते हैं। हालाँकि, newजब आप पूरे स्प्रिंग संदर्भ को लोड नहीं करना चाहते हैं तो यूनिट परीक्षणों में मैन्युअल रूप से ( कीवर्ड के साथ ) कक्षाओं को तुरंत रद्द करना बुरा नहीं है।


0

ध्यान रखें कि आपको स्प्रिंग कॉन्फ़िगरेशन फ़ाइल में @Autowiredतत्व जोड़कर एनोटेशन को सक्षम करना होगा <context:annotation-config/>। यह पंजीकरण करेगा AutowiredAnnotationBeanPostProcessorजो एनोटेशन के प्रसंस्करण का ध्यान रखता है।

और फिर आप फ़ील्ड इंजेक्शन विधि का उपयोग करके अपनी सेवा को स्वचालित कर सकते हैं।

public class YourController{

 @Autowired
 private UserService userService; 

}

मुझे यह पोस्ट स्प्रिंग @ अनॉउंटेड एनोटेशन से मिला


0

3 तरीके हैं जिनसे आप एक इंस्टेंस बना सकते हैं @Autowired

1. @Autowiredगुणों पर

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

    @Component("userService")
    public class UserService {

        public String getName() {
            return "service name";
        }
    }

    @Component
    public class UserController {

        @Autowired
        UserService userService

    }

उपरोक्त उदाहरण में, स्प्रिंग की तलाश की जाती है और निर्मित userServiceहोने पर उसे इंजेक्ट किया UserControllerजाता है।

2. सेट @Autowiredपर

@Autowiredएनोटेशन सेटर तरीकों पर इस्तेमाल किया जा सकता। नीचे दिए गए उदाहरण में, जब सेटर विधि पर एनोटेशन का उपयोग किया जाता है, तो सेट्टर विधि को बनाया जाने के userServiceसमय के उदाहरण के साथ कहा जाता UserControllerहै:

public class UserController {

    private UserService userService;

    @Autowired
    public void setUserService(UserService userService) {
            this.userService = userService;
    }
}

3. @Autowiredकंस्ट्रक्टर्स पर

@Autowiredएनोटेशन निर्माणकर्ता पर इस्तेमाल किया जा सकता है। नीचे दिए गए उदाहरण में, जब एक निर्माणकर्ता पर एनोटेशन का उपयोग किया जाता है, तो इसका एक उदाहरण userServiceनिर्माणकर्ता के तर्क के रूप में इंजेक्ट किया जाता है जब UserControllerबनाया जाता है:

public class UserController {

    private UserService userService;

    @Autowired
    public UserController(UserService userService) {
        this.userService= userService;
    }
}

0

सरल शब्दों में, स्वचालित रूप से वायरिंग लिंक, अब सवाल आता है कि यह कौन करता है और किस तरह का वायरिंग है। उत्तर है: कंटेनर ऐसा करता है और द्वितीयक प्रकार के तारों का समर्थन किया जाता है, आदिम को मैन्युअल रूप से करने की आवश्यकता होती है।

प्रश्न: कैसे कंटेनर पता है कि किस प्रकार की वायरिंग?

उत्तर: हम इसे बाईटाइप, बायनेम, कंस्ट्रक्टर के रूप में परिभाषित करते हैं।

प्रश्न: क्या ऐसे तरीके हैं जो हम प्रकार के ऑटोवेरिंग को परिभाषित नहीं करते हैं?

उत्तर: हां, यह एक एनोटेशन, @Autowired करके है।

प्रश्न: लेकिन सिस्टम कैसे जानता है, मुझे इस प्रकार के द्वितीयक डेटा को चुनने की आवश्यकता है?

उत्तर: आप उस डेटा को आपको स्प्रिंग.xml फ़ाइल में या अपनी कक्षा को स्टीरियोटाइप एनोटेशन का उपयोग करके प्रदान करेंगे ताकि कंटेनर स्वयं ही आपके लिए ऑब्जेक्ट बना सके।

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