Я хочу использовать аннотированный компонент-прототип в своем контроллере. Но вместо этого spring создает одноэлементный компонент. Вот код для этого:
@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}
В Spring config.xml
включено сканирование компонентов:
<context:annotation-config />
<context:component-scan base-package="com.springheat" />
<mvc:annotation-driven />
Каждый раз я получаю увеличивающийся счет. Не могу понять, где я ошибаюсь!
Обновить
Как было предложено @gkamal , я сделал HomeController
webApplicationContext
-aware и решил проблему.
обновленный код:
@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
Тинтин
источник
источник
Ответы:
Прототип области действия означает, что каждый раз, когда вы запрашиваете у spring (getBean или внедрение зависимости) экземпляр, он создает новый экземпляр и дает ссылку на него.
В вашем примере новый экземпляр LoginAction создается и вводится в ваш HomeController. Если у вас есть другой контроллер, в который вы вводите LoginAction, вы получите другой экземпляр.
Если вам нужен другой экземпляр для каждого вызова - тогда вам нужно каждый раз вызывать getBean - внедрение в одноэлементный компонент этого не приведет.
источник
request
вместоprototype
области была бы область видимости. Вам все еще нужно получить bean-компонент с помощьюcontext.getBean(..)
?Начиная с Spring 2.5, есть очень простой (и элегантный) способ добиться этого.
Вы можете просто изменения параметров
proxyMode
иvalue
в@Scope
аннотации.С помощью этой уловки вы можете избежать написания лишнего кода или внедрения ApplicationContext каждый раз, когда вам нужен прототип внутри одноэлементного bean-компонента.
Пример:
Конфигурация выше
LoginAction
(внутриHomeController
) всегда является прототипом, даже если контроллер синглтон .источник
Просто потому, что bean-компонент, введенный в контроллер, имеет область видимости прототипа, это не означает, что контроллер таковым!
источник
@controller - это одноэлементный объект, и если внедрить компонент-прототип в одноэлементный класс, он сделает его также одноэлементным, если только вы не укажете свойство lookup-method, которое фактически создает новый экземпляр компонента-прототипа для каждого вашего вызова.
источник
Как упоминал nicholas.hauschild, внедрение контекста Spring - не лучшая идея. В вашем случае достаточно @Scope ("request"), чтобы это исправить. Но допустим, вам нужно несколько экземпляров
LoginAction
метода контроллера. В этом случае я бы рекомендовал создать bean-компонент поставщика ( решение Spring 4 ):Затем введите его в контроллер:
источник
ObjectFactory
которые служат той же цели, что и поставщик, но могут быть определены как нормальные,@Bean
под которыми я подразумеваю отсутствие необходимости возвращать лямбду.Использование
ApplicationContextAware
привязывает вас к Spring (что может быть, а может и не быть проблемой). Я бы порекомендовал передать aLoginActionFactory
, который вы можете запрашиватьLoginAction
каждый раз, когда он вам нужен.источник
factory-method
здесь ...LoginActionFactory
в контроллер, ноfactory-method
похоже, что это не решит проблему, поскольку он просто создает другой компонент Spring через фабрику. Внедрение этого bean-компонента в одноэлементный контроллер не решит проблему.использовать область запроса
@Scope("request")
для получения bean-компонента для каждого запроса или@Scope("session")
для получения bean-компонента для каждого сеанса 'user'источник
Бин-прототип, внедренный внутри бина-одиночки, будет вести себя как бин-одиночка до тех пор, пока не будет явно вызван для создания нового экземпляра с помощью bean-компонента.
источник
@Составная часть
@Scope (значение = "прототипом")
открытый класс TennisCoach реализует Coach {
// некоторый код
}
источник
Вы можете создать статический класс внутри вашего контроллера следующим образом:
источник
Еще один способ решения проблемы - внедрение метода с аннотацией @Lookup .
Вот хорошая статья по этой проблеме внедрения компонентов-прототипов в одноэлементный экземпляр с несколькими решениями.
https://www.baeldung.com/spring-inject-prototype-bean-into-singleton
источник
Вашему контроллеру также нужен
@Scope("prototype")
определенныйкак это:
источник