Eu quero usar um protótipo de bean anotado no meu controlador. Mas a primavera está criando 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}
O Spring config.xml
tem a verificação de componentes ativada:
<context:annotation-config />
<context:component-scan base-package="com.springheat" />
<mvc:annotation-driven />
Estou recebendo uma contagem incrementada a cada vez. Não consigo descobrir onde estou errado!
Atualizar
Como sugerido por @gkamal , eu tomei HomeController
webApplicationContext
conhecimento 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");
}
}
spring
spring-mvc
tintim
fonte
fonte
Respostas:
O protótipo de escopo significa que toda vez que você solicitar uma mola (injeção de dependência ou getBean), ela criará uma nova instância e fornecerá 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 o LoginAction, receberá uma instância diferente.
Se você deseja uma instância diferente para cada chamada - é necessário chamar getBean a cada vez - a injeção em um bean singleton não conseguirá isso.
fonte
request
escopo em vez deprototype
escopo. Você ainda precisaria recuperar o beancontext.getBean(..)
?Desde a Primavera 2.5, existe uma maneira muito fácil (e elegante) de conseguir isso.
Você pode apenas alterar os parâmetros
proxyMode
evalue
a@Scope
anotação.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:
Com a configuração acima
LoginAction
(dentroHomeController
), sempre é um protótipo, mesmo que o controlador seja um singleton .fonte
Só porque o feijão injetado no controlador é do escopo do protótipo não significa que o controlador é!
fonte
@controller é um objeto singleton, e se injetar um protótipo de bean em uma classe singleton fará com que o protótipo também seja singleton, a menos que você especifique usando a propriedade lookup-method, que na verdade cria uma nova instância de prototype bean para cada chamada que você fizer.
fonte
Como mencionado por nicholas.hauschild, injetar o contexto da Primavera não é uma boa ideia. No seu caso, o @Scope ("request") é suficiente para corrigi-lo. Mas digamos que você precise de várias instâncias do
LoginAction
método no controlador. Nesse caso, eu recomendaria criar o bean do fornecedor ( solução da Primavera 4 ):Em seguida, injete-o no controlador:
fonte
ObjectFactory
que servem ao mesmo propósito do fornecedor, mas podem ser definidas como normais,@Bean
pelo que quero dizer que não há necessidade de devolver um lambda.O uso
ApplicationContextAware
está vinculando você ao Spring (o que pode ou não ser um problema). Eu recomendaria passar umLoginActionFactory
, que você pode solicitar uma nova instância deLoginAction
cada vez que precisar.fonte
factory-method
aqui ...LoginActionFactory
no Controller, masfactory-method
parece que isso não resolveria o problema, pois apenas cria outro bean de mola na fábrica. Injetar esse bean no controlador singleton não resolverá o problema.use o escopo da solicitação
@Scope("request")
para obter bean para cada solicitação ou@Scope("session")
para obter bean para cada sessão 'user'fonte
Um protoype bean injetado dentro de um singelton se comportará como singelton, até que seja exigido, de maneira exilada, a criação de uma nova instância por get bean.
fonte
@Componente
@Scope (valor = "protótipo")
a classe pública TennisCoach implementa o Coach {
// algum código
}
fonte
Você pode criar uma classe estática dentro do seu controlador assim:
fonte
Outra maneira de resolver o problema é a injeção de método com a anotação @Lookup .
Aqui está um bom artigo sobre esta questão de injeção de protótipo de beans em uma instância singleton com várias soluções.
https://www.baeldung.com/spring-inject-prototype-bean-into-singleton
fonte
Seu controlador também precisa do
@Scope("prototype")
definidocomo isso:
fonte