Escopo do bean @Scope (“prototype”) não criando um novo bean

Eu quero usar um bean protótipo anotado no meu controlador. Mas a primavera está criando um bean singleton. Aqui está o código para isso:

@Component @Scope("prototype") public class LoginAction { private int counter; public LoginAction(){ System.out.println(" counter is:" + counter); } public String getStr() { return " counter is:"+(++counter); } } 

Código do controlador:

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

Modelo de velocidade:

  LoginAction counter: ${loginAction.str} 

O Spring config.xml tem a verificação de componentes ativada:

     

Estou recebendo uma contagem incrementada a cada vez. Não consigo descobrir onde estou indo errado!

Atualizar

Como sugerido por @gkamal , tornei o HomeController webApplicationContext e resolvi o problema.

código atualizado:

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

Protótipo de escopo significa que toda vez que você perguntar por spring (getBean ou injeção de dependência) para uma instância, ele criará uma nova instância e dará uma referência a ela.

No seu exemplo, uma nova instância do LoginAction é criada e injetada no seu HomeController. Se você tiver outro controlador no qual você injeta LoginAction, você obterá uma instância diferente.

Se você quer uma instância diferente para cada chamada – então você precisa chamar getBean toda vez – injetar em um singleton bean não vai conseguir isso.

Só porque o bean injetado no controlador é protótipo-escopo não significa que o controlador é!

@controller é um object singleton, e se injetar um bean de protótipo em uma class singleton fará com que o bean de protótipo também seja singleton, a menos que você especifique usando a propriedade lookup-method que realmente cria uma nova instância de bean de protótipo para cada chamada.

Desde a spring 2.5, há uma maneira muito fácil (e elegante) de conseguir isso.

Você pode apenas alterar o params proxyMode e o value da anotação @Scope .

Com esse truque, você pode evitar escrever código extra ou injetar o ApplicationContext toda vez que precisar de um protótipo dentro de um bean singleton.

Exemplo:

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

Com a configuração acima de LoginAction (dentro de HomeController ) é sempre um protótipo , embora o controlador seja um singleton .

Use o escopo de solicitação @Scope("request") para obter bean para cada requisição, ou @Scope("session") para obter bean para cada session ‘user’

Como mencionado por nicholas.hauschild, injetar o contexto da primavera não é uma boa idéia. No seu caso, @Scope (“request”) é suficiente para consertá-lo. Mas vamos dizer que você precisa de várias instâncias do LoginAction no método do controlador. Nesse caso, recomendo criar o bean do fornecedor (solução Spring 4 ):

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

Em seguida, injetar no controlador:

 @Controller public class HomeController { @Autowired private Supplier loginActionSupplier; 

O uso do ApplicationContextAware está vinculando você ao Spring (que pode ou não ser um problema). Eu recomendaria passar um LoginActionFactory , que você pode pedir uma nova instância de uma LoginAction sempre que precisar de uma.

seu controlador também precisa do @Scope (“prototype”)

como isso:

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