2011-10-01 61 views
84

我想在控制器中使用帶註釋的原型bean。但是Spring正在創建一個singleton bean。下面是該代碼:@Scope(「prototype」)bean作用域不會創建新的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); 
    } 
} 

控制器代碼:

@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模板:

LoginAction counter: ${loginAction.str} 

春​​3210啓用組件掃描:

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

我每次都得到遞增的計數。無法弄清楚我哪裏錯了!

更新

由於suggested by @gkamal,我做了HomeControllerwebApplicationContext知曉的,它解決了這個問題。

更新的代碼:

@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

我想我可能會增加一倍給予好評您實現對正確答案你的代碼讓其他人看到實際的差異 –

回答

104

範圍原型意味着每次一個實例它會創建一個新的實例,並給一個參考問彈簧(或的getBean依賴注入)。

在你的例子中,一個新的LoginAction實例被創建並注入到你的HomeController中。如果您有其他控制器注入LoginAction,您將獲得不同的實例。

如果你想爲每個調用使用不同的實例 - 那麼你需要每次都調用getBean - 注入單例bean不會達到這個目的。

+5

我製作了控制器ApplicationContextAware並做了getBean,我每次都得到鮮豆。多謝你們!!! – tintin

+0

如果bean有'request'範圍而不是'prototype'範圍,這是如何工作的。你還需要用'context.getBean(..)'來檢索bean嗎? –

+0

或者使用作用域代理,即@Scope(value =「prototype」,proxyMode = ScopedProxyMode.TARGET_CLASS) – svenmeier

12

僅僅因爲注入控制器的bean是原型範圍的,並不意味着控制器是!

2

使用ApplicationContextAware將您綁定到Spring(可能會或可能不是問題)。我建議通過LoginActionFactory,你可以在每次需要的時候請求一個LoginAction的新實例。

+1

雖然已經有了特定於Spring的註釋,似乎並不是那麼重要。 –

+1

@Dave,好點。對於一些DI的東西(JSR 311)還有其他的選擇,但是在這個例子中,可能很難擺脫Spring依賴的所有東西。我想我真的只是在這裏提倡'工廠方法'... –

+1

+1,用於將單例LoginActionFactory注入到Controller中,但是'factory-method'似乎不能解決問題,因爲它只是通過工廠創建另一個春豆。將該bean注入單例控制器不會解決問題。 –

-6

控制器還需要@Scope(「原型」)defind

這樣的:

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

} 
+0

爲什麼你認爲控制器還需要原型? –

+5

這顯然是錯誤的。 –

7

@Controller是一個單獨的對象,如果一個原型的bean注入到一個單例類將使原型bean也是單身人士,除非你指定使用lookup-method屬性,它爲每次調用創建一個新的prototype bean實例。

3

使用請求範圍@Scope("request")獲得豆爲每個請求,或@Scope("session")讓每個會話「用戶」

2

如前所述通過nicholas.hauschild注入Spring上下文是不是一個好主意豆。在你的情況下,@Scope(「請求」)就足以解決它。但假設你需要在控制器方法中使用LoginAction的幾個實例。在這種情況下,我建議建立供應商的綠豆(Spring 4溶液):

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

然後將其注入控制器:

@Controller 
public class HomeController { 
    @Autowired 
    private Supplier<LoginAction> loginActionSupplier; 
相關問題