que - spring mvc tutorial español pdf
@Scope("prototype") bean scope no crea nuevos beans (8)
¡Solo porque el frijol inyectado en el controlador tenga un alcance de prototipo no significa que el controlador sí lo esté!
Quiero usar un prototipo de frijol anotado en mi controlador. Pero la primavera está creando un frijol singleton 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 escaneo de componentes habilitado:
<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
Como lo sugirió @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");
}
}
@controller es un objeto singleton, y si se inyecta un bean prototipo a una clase singleton, el prototipo bean también será singleton a menos que se especifique usando la propiedad lookup-method que realmente crea una nueva instancia de prototype bean para cada llamada que hagas.
Como lo menciona nicholas.hauschild inyectando el contexto de primavera no es una buena idea. En su caso, @Scope ("solicitud") es suficiente para solucionarlo. Pero supongamos que necesita varias instancias de LoginAction
en el método del controlador. En este caso, recomendaría crear el bean de Supplier (solución Spring 4 ):
@Bean
public Supplier<LoginAction> loginActionSupplier(LoginAction loginAction){
return () -> loginAction;
}
Luego inyectalo en el controlador:
@Controller
public class HomeController {
@Autowired
private Supplier<LoginAction> loginActionSupplier;
Desde Spring 2.5 hay una manera muy fácil (y elegante) de lograr eso.
Solo puede cambiar el modo proxyMode
y el value
de la anotación @Scope
.
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:
@Service
@Scope(value="prototype", proxyMode=ScopedProxyMode.TARGET_CLASS)
public class LoginAction {}
Con la configuración anterior, LoginAction
(dentro de HomeController
) siempre es un prototipo aunque el controlador sea singleton .
El prototipo del alcance significa que cada vez que solicite la primavera (getBean o inyección de dependencia) para una instancia, creará una nueva instancia y dará una referencia a eso.
En su ejemplo, se crea una nueva instancia de LoginAction y se inyecta en su HomeController. Si tienes otro controlador en el que inyectas LoginAction obtendrás una instancia diferente.
Si desea una instancia diferente para cada llamada, debe llamar a getBean cada vez; inyectar en un bean singleton no lo logrará.
Usar ApplicationContextAware
está atando a Spring (que puede o no ser un problema). Yo recomendaría pasar una LoginActionFactory
, que puede solicitar una nueva instancia de LoginAction
cada vez que la necesite.
su controlador también necesita el ajuste de @Scope ("prototipo")
Me gusta esto:
@Controller
@Scope("prototype")
public class HomeController {
.....
.....
.....
}
use el alcance de solicitud @Scope("request")
para obtener bean para cada solicitud, o @Scope("session")
para obtener bean para cada sesión ''usuario''