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.xml
tiene 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
request
alcance en lugar deprototype
alcance? ¿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
proxyMode
yvalue
la@Scope
anotació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
LoginAction
método en el controlador. En este caso, recomendaría crear el bean de proveedor ( solución Spring 4 ):Luego inyectarlo en el controlador:
fuente
ObjectFactory
que sirven para el mismo propósito que el proveedor, pero se pueden definir como normales,@Bean
lo que significa que no es necesario devolver una lambda.Usar te
ApplicationContextAware
está atando a Spring (lo que puede o no ser un problema). Recomendaría pasar unLoginActionFactory
, que puede solicitar una nueva instancia deLoginAction
cada vez que lo necesite.fuente
factory-method
aquí ...LoginActionFactory
en el Controlador, perofactory-method
no 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