2011-10-01 139 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;