Quiero usar un prototipo de bean anotado en mi controlador. Pero la primavera está creando un grano único en su lugar. Aquí está el código para eso:
@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 del 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;
}
}
Plantilla de velocidad:
LoginAction counter: ${loginAction.str}
Spring config.xmltiene habilitado el escaneo de componentes:
<context:annotation-config />
<context:component-scan base-package="com.springheat" />
<mvc:annotation-driven />
Recibo un recuento incrementado cada vez. ¡No puedo entender dónde me estoy equivocando!
Actualizar
Según lo sugerido por @gkamal , hice HomeController webApplicationContext-aware y resolvió el 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");
}
}
spring
spring-mvc
tintin
fuente
fuente

Respuestas:
El prototipo de alcance significa que cada vez que solicite a spring (getBean o inyección de dependencia) una instancia, creará una nueva instancia y le dará una referencia.
En su ejemplo, se crea una nueva instancia de LoginAction y se inyecta en su HomeController. Si tiene otro controlador en el que inyecta LoginAction obtendrá una instancia diferente.
Si desea una instancia diferente para cada llamada, entonces necesita llamar a getBean cada vez, inyectar en un bean singleton no lo logrará.
fuente
requestalcance en lugar deprototypealcance? ¿Aún necesitarías recuperar el frijolcontext.getBean(..)?Desde Spring 2.5 hay una manera muy fácil (y elegante) de lograrlo.
Simplemente puede cambiar los parámetros
proxyModeyvaluela@Scopeanotación.Con este truco, puede evitar escribir código adicional o inyectar el ApplicationContext cada vez que necesite un prototipo dentro de un bean singleton.
Ejemplo:
Con la configuración anterior
LoginAction(dentroHomeController) siempre es un prototipo a pesar de que el controlador es un singleton .fuente
El hecho de que el bean inyectado en el controlador tenga un alcance prototipo no significa que el controlador lo esté.
fuente
@controller es un objeto singleton, y si se inyecta un bean prototipo a una clase singleton, el bean prototipo también se convertirá en singleton a menos que especifique el uso de la propiedad del método de búsqueda que realmente crea una nueva instancia de bean prototipo para cada llamada que realice.
fuente
Como lo mencionó nicholas.hauschild inyectando el contexto Spring no es una buena idea. En su caso, @Scope ("solicitud") es suficiente para solucionarlo. Pero supongamos que necesita varias instancias del
LoginActionmétodo en el controlador. En este caso, recomendaría crear el bean de proveedor ( solución Spring 4 ):Luego inyectarlo en el controlador:
fuente
ObjectFactoryque sirven para el mismo propósito que el proveedor, pero se pueden definir como normales,@Beanlo que significa que no es necesario devolver una lambda.Usar te
ApplicationContextAwareestá atando a Spring (lo que puede o no ser un problema). Recomendaría pasar unLoginActionFactory, que puede solicitar una nueva instancia deLoginActioncada vez que lo necesite.fuente
factory-methodaquí ...LoginActionFactoryen el Controlador, perofactory-methodno parece que resolvería el problema, ya que solo crea otro grano de primavera a través de la fábrica. Inyectar ese bean en el controlador singleton no resolverá el problema.use el alcance de la solicitud
@Scope("request")para obtener un bean para cada solicitud, o@Scope("session")para obtener un bean para cada 'usuario' de sesiónfuente
Un bean prototipo inyectado dentro de un bean singelton se comportará como singelton hasta que se solicite explícitamente la creación de una nueva instancia mediante get bean.
fuente
@Componente
@Scope (valor = "prototipo")
clase pública TennisCoach implementa Coach {
// algún código
}
fuente
Puede crear una clase estática dentro de su controlador de esta manera:
fuente
Otra forma de resolver el problema es la inyección de métodos con la anotación @Lookup .
Aquí hay un buen artículo sobre este tema de inyectar prototipos de beans en una instancia singleton con múltiples soluciones.
https://www.baeldung.com/spring-inject-prototype-bean-into-singleton
fuente
Su controlador también necesita el
@Scope("prototype")definidoMe gusta esto:
fuente