2011-10-01 16 views
84

Chcę użyć adnotowanej fasoli prototypowej w moim kontrolerze. Ale wiosna tworzy zamiast tego pojedynczą fasolę. Oto kod, który:@ Beope ("prototyp") zakres komponentu bean nie tworząc nowego komponentu bean

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

    private int counter; 

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

kod Kontroler:

@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; 
    } 
    } 

Velocity szablon:

LoginAction counter: ${loginAction.str} 

Wiosna config.xml ma skanowanie komponentu włączone:

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

Za każdym razem otrzymuję inkrementowaną liczbę. Nie mogę się domyślić, co się dzieje źle!

Aktualizacja

Jak suggested by @gkamal, zrobiłem HomeControllerwebApplicationContext -aware i to rozwiązało problem.

zaktualizowany kod:

@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"); 
    } 
} 
+7

Chciałbym podwoić upvote ciebie za wdrażanie poprawną odpowiedź w Twój kod dla innych, aby zobaczyć rzeczywistą różnicę –

Odpowiedz

104

prototyp Zakres oznacza, że ​​za każdym razem prosić sprężynę (getBean lub iniekcji zależność) dla instancji stworzy nową instancję i dać odniesienie do tego.

W twoim przykładzie nowa instancja LoginAction jest tworzona i wstrzykiwana do twojego HomeController. Jeśli masz inny kontroler, do którego wstrzykujesz LoginAction, dostaniesz inną instancję.

Jeśli chcesz mieć inną instancję dla każdego połączenia - musisz za każdym razem wywołać funkcję getBean - nie uda się tego zaszczepić w pojedynczą fasolkę.

+5

Zrobiłem kontroler ApplicationContextAware i zrobiłem getBean i za każdym razem otrzymuję świeżą fasolkę. Dzięki chłopaki!!! – tintin

+0

Jak to działa, jeśli komponent bean miałby zasięg 'request' zamiast zakresu' prototype'. Czy nadal potrzebujesz odzyskać komponent bean za pomocą 'context.getBean (..)'? –

+0

Lub użyj zakresowego proxy, np. @Scope (wartość = "prototyp", proxyMode = ScopedProxyMode.TARGET_CLASS) – svenmeier

12

To, że fasola wprowadzona do kontrolera ma zasięg prototypu, nie oznacza, że ​​kontroler jest!

2

Korzystanie z ApplicationContextAware wiąże cię z wiosną (co może, ale nie musi być problemem). Polecam przekazanie w postaci LoginActionFactory, za którą można poprosić o nowe wystąpienie numeru LoginAction za każdym razem, gdy go potrzebujesz.

+1

Istnieją już jednak adnotacje typu Spring; nie wydaje się, że to bardzo niepokojące. –

+1

@Dave, dobry punkt. Istnieją alternatywy dla niektórych elementów DI (JSR 311), ale może być trudniej pozbyć się wszystkiego W zależności od tego w Spring zależy. Przypuszczam, że naprawdę popieram "metodę fabryczną" tutaj ... –

+1

+1 za wstrzyknięcie singleton 'LoginActionFactory' do kontrolera, ale' factory-method' nie wydaje się, żeby to rozwiązało problem, ponieważ po prostu tworzy kolejną fasolę wiosenną przez fabrykę. Wstrzykiwanie tego komponentu do kontrolera singleton nie rozwiąże problemu. –

-6

kontroler potrzebują również @Scope ("prototyp") defind

takiego:

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

} 
+0

dlaczego uważasz, że kontroler również musi być prototypem? –

+5

To jest po prostu źle. –

7

@controller jest pojedyncza obiektu, a jeśli wstrzyknąć fasoli prototypu do klasy singleton uczynią prototypowy komponent bean również jako singleton, chyba że określisz metodę lookup-method, która faktycznie tworzy nowe wystąpienie prototypowego komponentu bean dla każdego wywoływanego połączenia.

3

użycie prośba zakres @Scope("request") dostać fasoli na każde żądanie lub @Scope("session") dostać fasoli dla każdej sesji „user”

2

Jak wspomniano przez nicholas.hauschild wstrzykiwanie kontekst sprężyna nie jest dobrym pomysłem. W twoim przypadku @Scope ("request") wystarczy, aby to naprawić. Ale powiedzmy, że potrzebujesz kilku instancji LoginAction w metodzie sterownika.W tym przypadku, polecam, aby utworzyć ziarna dostawcy (Spring 4 roztwór):

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

Następnie wstrzyknąć go do kontrolera:

@Controller 
public class HomeController { 
    @Autowired 
    private Supplier<LoginAction> loginActionSupplier; 
Powiązane problemy