@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, я сделал HomeControllerwebApplicationContext-известно, и это решило проблему.

обновленный код:

@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 97

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;  

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

ваш контроллер также нуждается в @ Scope("прототип") defind

такой:

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

}