@Scope ("prototype") Bean scope not creating new bean

Quero usar um protótipo de feijão anotado no meu controlador. Mas a primavera está a criar um feijão 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}

A mola config.xml tem a digitalização de componentes activada:

    <context:annotation-config />
    <context:component-scan base-package="com.springheat" />
    <mvc:annotation-driven />
Estou a receber uma contagem crescente de cada vez. Não consigo perceber para onde estou a ir mal!

actualizar

Como sugerido por @gkamal, eu fiz HomeController webApplicationContext-ciente e resolveu o problema.

Código actualizado:

@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");
    }
}
Author: thlim, 2011-10-01

8 answers

O protótipo de âmbito significa que cada vez que se pede a injecção de primavera (getBean ou dependency injection), por exemplo, irá criar uma nova instância e dar uma referência a isso.

No seu exemplo, uma nova instância de Loginacção é criada e injectada no seu controlador de casa . Se tiver outro controlador no qual injecta a Loginacção, terá uma instância diferente.

Se quiser uma instância diferente para cada chamada - então precisa de ligar ao getBean de cada vez que estiver a injectar num feijão singleton não vai conseguir isso.

 118
Author: gkamal, 2011-10-01 18:00:29
Só porque o feijão injectado no controlador tem uma mira de protótipo, não significa que o controlador esteja!
 14
Author: Dave Newton, 2011-10-01 18:01:54

@controller is a singleton object, and if injecte a prototype bean to a singleton class will make the prototype bean also as singleton unless u specify using lookup-method property which actually create a new instance of prototype bean for every call you make.

 8
Author: kartheek, 2012-12-13 17:29:12
Desde a Primavera 2.5 há uma maneira muito fácil (e elegante) de conseguir isso.

Podes mudar os parâmetros proxyMode e value da anotação @Scope.

Com este truque, pode evitar escrever um código extra ou injectar o texto de Aplicação sempre que precisar de um protótipo dentro de um feijão singleton.

Exemplo:

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

Com a configuração acima LoginAction (no interior HomeController) é sempre um protótipo mesmo que o controlador seja um singleton .

 5
Author: db80, 2018-05-22 14:20:09

Usar o âmbito do pedido {[[0]} para obter o bean para cada pedido, ou @Scope("session") para obter o bean para cada sessão 'utilizador'

 3
Author: Bassem Reda Zohdy, 2015-03-19 14:36:39

Como mencionado por nicholas.a injecção do contexto da primavera não é uma boa ideia. No seu caso, @Scope ("pedido") é suficiente para corrigi-lo. Mas deixe-me dizer que você precisa de várias instâncias de LoginAction no método do controlador. Neste caso, eu recomendaria criar o feijão do Fornecedor ([[7]}Spring 4 solução):

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

Depois injecte-o no controlador:

@Controller
public class HomeController {
    @Autowired
    private  Supplier<LoginAction> loginActionSupplier;  
 3
Author: Igor Rybak, 2017-07-27 18:51:53

Usar {[[0]} está a ligar-te à Primavera (o que pode ou não ser um problema). Eu recomendaria passar em um LoginActionFactory, que você pode pedir uma nova instância de um LoginAction cada vez que você precisa de um.

 2
Author: nicholas.hauschild, 2013-02-21 15:40:31

O seu controlador também precisa do @Scope ("protótipo") defind

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

}
 -8
Author: flyerfang, 2012-04-14 14:40:31