Область действия компонента @Scope ("prototype") не создает новый компонент - PullRequest
114 голосов
/ 01 октября 2011

Я хочу использовать аннотированный компонент-прототип в моем контроллере.Но весна вместо этого создает синглтон.Вот код для этого:

@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");
    }
}

Ответы [ 10 ]

137 голосов
/ 01 октября 2011

Прототип Scope означает, что каждый раз, когда вы запрашиваете у Spring (getBean или внедрение зависимостей) экземпляр, он создает новый экземпляр и дает ссылку на него.

В вашем примере создается новый экземпляр LoginActionи вводится в ваш HomeController.Если у вас есть другой контроллер, в который вы вводите LoginAction, вы получите другой экземпляр.

Если вам нужен другой экземпляр для каждого вызова - тогда вам нужно каждый раз вызывать getBean - внедрение в одноэлементный компонент не дастчто.

13 голосов
/ 30 марта 2018

С весны 2.5 есть очень простой (и элегантный) способ добиться этого.

Вы можете просто изменить параметры proxyMode и value аннотации @Scope.

С помощью этого трюка вы можете избежать написания дополнительного кода или внедрения ApplicationContext каждый раз, когда вам нужен прототип внутри одноэлементного компонента.

Пример:

@Service 
@Scope(value="prototype", proxyMode=ScopedProxyMode.TARGET_CLASS)  
public class LoginAction {}

С приведенной выше конфигурацией LoginAction (внутри HomeController) всегда является прототипом , хотя контроллером является singleton .

12 голосов
/ 01 октября 2011

То, что компонент, введенный в контроллер, имеет прототипную область, не означает, что контроллер является!

9 голосов
/ 13 декабря 2012

@ controller является одноэлементным объектом, и если внедрить bean-компонент-прототип в одноэлементный класс, то bean-объект-прототип также будет превращен в одноэлементный, если только вы не укажете, используя свойство lookup-method, которое фактически создает новый экземпляр bean-компонента-прототипа для каждого выполняемого вами вызова.,

4 голосов
/ 27 июля 2017

Как упомянуто nicholas.hauschild внедрение контекста Spring - не очень хорошая идея. В вашем случае @Scope («request») достаточно, чтобы это исправить. Но допустим, вам нужно несколько экземпляров LoginAction в методе контроллера. В этом случае я бы порекомендовал создать компонент поставщика (решение Spring 4 ):

    @Bean
    public Supplier<LoginAction> loginActionSupplier(LoginAction loginAction){
        return () -> loginAction;
    }

Затем введите его в контроллер:

@Controller
public class HomeController {
    @Autowired
    private  Supplier<LoginAction> loginActionSupplier;  
3 голосов
/ 19 марта 2015

используйте область запроса @Scope("request"), чтобы получить бин для каждого запроса, или @Scope("session"), чтобы получить бин для каждого сеанса 'user'

3 голосов
/ 01 октября 2011

Использование ApplicationContextAware привязывает вас к Spring (что может быть, а может и не быть проблемой). Я бы порекомендовал передать LoginActionFactory, который вы можете запросить для нового экземпляра LoginAction каждый раз, когда он вам нужен.

0 голосов
/ 28 июня 2019

@ Компонент

@ Scope (значение = "прототип")

Публичный класс TennisCoach реализует Coach {

// некоторый код

}

0 голосов
/ 08 декабря 2018

Бин-прототип, внедренный в бин синглтона, будет вести себя как сингелтон до тех пор, пока не будет вызвано создание нового экземпляра с помощью get bean.

context.getBean("Your Bean")
0 голосов
/ 14 апреля 2012

вашему контроллеру также необходимо определение @Scope ("prototype")

как это:

@Controller
@Scope("prototype")
public class HomeController { 
 .....
 .....
 .....

}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...