@ स्कोप ("प्रोटोटाइप") बीन गुंजाइश नई बीन नहीं बना रही है


133

मैं अपने नियंत्रक में एक एनोटेट प्रोटोटाइप बीन का उपयोग करना चाहता हूं। लेकिन वसंत इसके बजाय एक सिंगल बीन बना रहा है। यहाँ उस के लिए कोड है:

@Component
@Scope("prototype")
public class LoginAction {

  private int counter;

  public LoginAction(){
    System.out.println(" counter is:" + counter);
  }
  public String getStr() {
    return " counter is:"+(++counter);
  }
}

नियंत्रक कोड:

@Controller
public class HomeController {
    @Autowired
    private LoginAction loginAction;

    @RequestMapping(value="/view", method=RequestMethod.GET)
    public ModelAndView display(HttpServletRequest req){
        ModelAndView mav = new ModelAndView("home");
        mav.addObject("loginAction", loginAction);
        return mav;
    }

    public void setLoginAction(LoginAction loginAction) {
        this.loginAction = loginAction;
    }

    public LoginAction getLoginAction() {
        return loginAction;
    }
    }

वेग टेम्पलेट:

 LoginAction counter: ${loginAction.str}

स्प्रिंग config.xmlमें घटक स्कैनिंग सक्षम है:

    <context:annotation-config />
    <context:component-scan base-package="com.springheat" />
    <mvc:annotation-driven />

मुझे हर बार एक इंक्रीमेंट मिल रहा है। पता नहीं लगा सकता कि मैं कहाँ गलत हूँ!

अपडेट करें

जैसा कि @gkamal द्वारा सुझाया गया है , मैंने किया- HomeController webApplicationContextअनभिज्ञ और इसने समस्या को हल किया।

अद्यतन कोड:

@Controller
public class HomeController {

    @Autowired
    private WebApplicationContext context;

    @RequestMapping(value="/view", method=RequestMethod.GET)
    public ModelAndView display(HttpServletRequest req){
        ModelAndView mav = new ModelAndView("home");
        mav.addObject("loginAction", getLoginAction());
        return mav;
    }

    public LoginAction getLoginAction() {
        return (LoginAction) context.getBean("loginAction");
    }
}

12
मेरी इच्छा है कि मैं वास्तविक अंतर को देखने के लिए दूसरों के लिए अपने कोड में सही उत्तर को लागू करने के लिए आपको दोगुना कर सकता हूं
अली नेम

जवाबों:


156

स्कोप प्रोटोटाइप का मतलब है कि हर बार जब आप वसंत (गेटबीन या निर्भरता इंजेक्शन) से पूछते हैं तो यह एक नया उदाहरण बनाएगा और इसका एक संदर्भ देगा।

आपके उदाहरण में LoginAction का एक नया उदाहरण बनाया गया है और आपके HomeController में इंजेक्ट किया गया है। यदि आपके पास एक और नियंत्रक है जिसमें आप LoginAction इंजेक्ट करते हैं तो आपको एक अलग उदाहरण मिलेगा।

यदि आप प्रत्येक कॉल के लिए एक अलग उदाहरण चाहते हैं - तो आपको प्रत्येक बार getBean कॉल करने की आवश्यकता है - एक सिंगलटन बीन में इंजेक्शन लगाने से वह हासिल नहीं होगा।


7
मैंने कंट्रोलर ApplicationContextAware बनाया और getBean किया और मुझे हर बार ताजा बीन मिल रहा है। धन्यवाद दोस्तों!!!
टिंचिन

अगर बीन में requestस्कोप की जगह होती तो यह कैसे काम करता prototype। क्या आपको अभी भी बीन को फिर से प्राप्त करना होगा context.getBean(..)?
डॉ जेरी

2
या स्कूप्ड प्रॉक्सी का उपयोग करें, यानी @Scope (मान = "प्रोटोटाइप", प्रॉक्सीमोड = ScopedProxyMode.TARGET_CLASS)
सेवेनियर

25

वसंत 2.5 के बाद से इसे प्राप्त करने का एक बहुत आसान (और सुरुचिपूर्ण) तरीका है।

तुम बस पैरामीटर बदल सकते हैं proxyModeऔर valueकी @Scopeव्याख्या।

इस ट्रिक से आप हर बार अतिरिक्त कोड लिखने या ApplicationContext को इंजेक्ट करने से बच सकते हैं, जिसके लिए आपको सिंगलटन बीन के अंदर एक प्रोटोटाइप की आवश्यकता होती है।

उदाहरण:

@Service 
@Scope(value="prototype", proxyMode=ScopedProxyMode.TARGET_CLASS)  
public class LoginAction {}

ऊपर विन्यास के साथ LoginAction(अंदर HomeController) हमेशा एक प्रोटोटाइप होता है भले ही नियंत्रक एक सिंगलटन हो


2
तो हम वसंत 5 में अब नहीं है?
रघुवीर

16

सिर्फ इसलिए कि बीन को कंट्रोलर में इंजेक्ट किया जाता है, प्रोटोटाइप-स्कोप का मतलब यह नहीं है कि कंट्रोलर है!


11

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


5

जैसा कि nicholas.hauschild द्वारा उल्लेख किया गया है वसंत संदर्भ इंजेक्शन एक अच्छा विचार नहीं है। आपके मामले में, @Scope ("अनुरोध") इसे ठीक करने के लिए पर्याप्त है। लेकिन मान लें कि आपको LoginActionनियंत्रक विधि में कई उदाहरणों की आवश्यकता है । इस मामले में, मैं आपूर्तिकर्ता की बीन ( स्प्रिंग 4 समाधान) बनाने की सिफारिश करूंगा :

    @Bean
    public Supplier<LoginAction> loginActionSupplier(LoginAction loginAction){
        return () -> loginAction;
    }

फिर इसे कंट्रोलर में इंजेक्ट करें:

@Controller
public class HomeController {
    @Autowired
    private  Supplier<LoginAction> loginActionSupplier;  

1
मैं स्प्रिंग्स को इंजेक्ट करने का सुझाव दूंगा ObjectFactoryजो आपूर्तिकर्ता के समान उद्देश्य को पूरा करता है, लेकिन इसे एक सामान्य के रूप में परिभाषित किया जा सकता @Beanहै, जिसका अर्थ है कि मुझे लैम्बडा वापस करने की कोई आवश्यकता नहीं है।
xenoterracide

3

उपयोग करना ApplicationContextAwareआपको स्प्रिंग से बांध रहा है (जो एक मुद्दा हो सकता है या नहीं भी हो सकता है)। मैं इसमें पास होने की सलाह दूंगा LoginActionFactory, जिसे आप LoginActionहर बार एक नए उदाहरण के लिए पूछ सकते हैं जो आपको चाहिए ।


1
हालांकि पहले से ही स्प्रिंग-विशिष्ट एनोटेशन हैं; ऐसा नहीं लगता कि यह एक चिंता का विषय है।
डेव न्यूटन

1
@ देदो, अच्छी बात है। DI सामान (JSR 311) में से कुछ के लिए विकल्प हैं, लेकिन इस उदाहरण में वसंत पर निर्भर सब कुछ से छुटकारा पाना कठिन हो सकता है। मुझे लगता है मैं वास्तव में factory-methodयहाँ की वकालत कर रहा हूँ ...
nicholas.hauschild

1
एक LoginActionFactoryनियंत्रक में एक सिंगलटन इंजेक्ट करने के लिए +1 , लेकिन factory-methodऐसा नहीं लगता कि यह समस्या को हल करेगा क्योंकि यह सिर्फ कारखाने के माध्यम से एक और स्प्रिंग बीन बनाता है। उस बीन को सिंगलटन कंट्रोलर में डालने से समस्या का समाधान नहीं होगा।
ब्रैड कपिट

अच्छा बिंदु ब्रैड, मैं अपने उत्तर से उस सुझाव को हटा दूंगा।
nicholas.hauschild

3

@Scope("request")प्रत्येक अनुरोध के @Scope("session")लिए बीन प्राप्त करने के लिए या प्रत्येक सत्र 'उपयोगकर्ता' के लिए बीन प्राप्त करने के लिए अनुरोध गुंजाइश का उपयोग करें


1

एक सिंगलटन बीन के अंदर इंजेक्ट किया गया एक प्रोटिओपियन बीन सिंगेलटन अनिल की तरह व्यवहार करेगा, जिसे सेम प्राप्त करके एक नया उदाहरण बनाने के लिए निष्कासित किया जाएगा।

context.getBean("Your Bean")


0

आप इस तरह अपने कंट्रोलर के अंदर स्टैटिक क्लास बना सकते हैं:

    @Controller
    public class HomeController {
        @Autowired
        private LoginServiceConfiguration loginServiceConfiguration;

        @RequestMapping(value = "/view", method = RequestMethod.GET)
        public ModelAndView display(HttpServletRequest req) {
            ModelAndView mav = new ModelAndView("home");
            mav.addObject("loginAction", loginServiceConfiguration.loginAction());
            return mav;
        }


        @Configuration
        public static class LoginServiceConfiguration {

            @Bean(name = "loginActionBean")
            @Scope("prototype")
            public LoginAction loginAction() {
                return new LoginAction();
            }
        }
}

0

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

समस्या को हल करने का दूसरा तरीका है @Lookup एनोटेशन के साथ विधि इंजेक्शन ।

यहाँ एक एकल उदाहरण में प्रोटोटाइप सेम इंजेक्शन के इस मुद्दे पर एक अच्छा लेख है कई समाधानों के साथ ।

https://www.baeldung.com/spring-inject-prototype-bean-into-singleton


-11

आपके नियंत्रक की भी आवश्यकता है @Scope("prototype") परिभाषित की है

इस तरह:

@Controller
@Scope("prototype")
public class HomeController { 
 .....
 .....
 .....

}

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