@Scope ("prototype") Bean scope not creating new 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);
}
}
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");
}
}
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.
@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.
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 .
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'
@Bean
public Supplier<LoginAction> loginActionSupplier(LoginAction loginAction){
return () -> loginAction;
}
Depois injecte-o no controlador:
@Controller
public class HomeController {
@Autowired
private Supplier<LoginAction> loginActionSupplier;
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.
O seu controlador também precisa do @Scope ("protótipo") defind
Assim:@Controller
@Scope("prototype")
public class HomeController {
.....
.....
.....
}