@Scope ("прототип") bean scope не создает новый bean
Я хочу использовать аннотированный прототип 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);
}
}
код контроллера:
@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;
}
}
шаблон скорость:
LoginAction counter: ${loginAction.str}
Весна config.xml
включено сканирование компонентов:
<context:annotation-config />
<context:component-scan base-package="com.springheat" />
<mvc:annotation-driven />
Я получаю увеличенное количество каждый раз. Не могу понять, где я ошибаюсь!
обновление
как было предложено по @gkamal, я сделал HomeController
webApplicationContext
-известно, и это решило проблему.
обновленный код:
@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 ответов:
scope prototype означает, что каждый раз, когда вы спрашиваете spring (getBean или Dependency injection) для экземпляра, он создаст новый экземпляр и даст ссылку на него.
в вашем примере создается новый экземпляр LoginAction и вводится в ваш HomeController . Если у вас есть другой контроллер, в который вы вводите LoginAction, вы получите другой экземпляр.
Если вы хотите другой экземпляр для каждого вызова-то вам нужно вызвать getBean каждый раз - инъекция в одноэлементный Боб этого не достигнет.
только потому, что Боб, введенный в контроллер, является прототипом, это не значит, что контроллер есть!
@controller-это одноэлементный объект, и если ввести прототип bean в одноэлементный класс, прототип bean также будет выполнен как одноэлементный, если u не укажет с помощью свойства lookup-method, которое фактически создает новый экземпляр прототипа bean для каждого выполняемого вызова.
С 2.5 есть очень простой (и элегантный) способ добиться этого.
вы можете просто изменить параметры
proxyMode
иvalue
на@Scope
Примечание.С помощью этого трюка вы можете избежать писать дополнительный код или вводить ApplicationContext каждый раз, когда вам нужен прототип внутри одноэлементного компонента.
пример:
@Service @Scope(value="prototype", proxyMode=ScopedProxyMode.TARGET_CLASS) public class LoginAction {}
с конфигурацией выше
LoginAction
(внутриHomeController
) всегда a прототип даже если контроллер является синглтон.
использовать контекст запроса
@Scope("request")
чтобы получить боб для каждого запроса, или@Scope("session")
чтобы получить боб для каждого сеанса "пользователь"
как отметил Николая.хаушильд впрыскивать весенний контекст не очень хорошая идея. В вашем случае, @Scope ("запрос") достаточно, чтобы исправить это. Но допустим вам нужно несколько экземпляров
LoginAction
в метод контроллера. В этом случае я бы рекомендовал создать фасоль поставщика (Весна 4 решение):@Bean public Supplier<LoginAction> loginActionSupplier(LoginAction loginAction){ return () -> loginAction; }
затем введите его в контроллер:
@Controller public class HomeController { @Autowired private Supplier<LoginAction> loginActionSupplier;