Подтвердить что ты не робот

@Scope( "prototype" ) bean область, не создающая новый bean

Я хочу использовать аннотированный компонент-прототип в моем контроллере. Но 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");
    }
}
4b9b3361

Ответ 1

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

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

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

Ответ 2

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

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

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

Пример:

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

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

Ответ 3

Просто потому, что введенный в контроллер bean прототип не означает, что контроллер!

Ответ 4

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

Ответ 5

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

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

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

@Controller
public class HomeController {
    @Autowired
    private  Supplier<LoginAction> loginActionSupplier;  

Ответ 6

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

Ответ 7

использовать область запроса @Scope("request") для получения bean для каждого запроса или @Scope("session") для получения bean для каждого пользователя сеанса

Ответ 8

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

context.getBean("Your Bean")

Ответ 9

@Составная часть

@Scope (value = "прототипом")

Открытый класс TennisCoach реализует Coach {

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

}

Ответ 10

Вы можете создать статический класс внутри вашего контроллера следующим образом:

    @Controller
    public class HomeController {
        @Autowired
        private LoginServiceConfiguration loginServiceConfiguration;

        @RequestMapping(value = "/view", method = RequestMethod.GET)
        public ModelAndView display(HttpServletRequest req) {
            ModelAndView mav = new ModelAndView("home");
            mav.addObject("loginAction", loginServiceConfiguration.loginAction());
            return mav;
        }


        @Configuration
        public static class LoginServiceConfiguration {

            @Bean(name = "loginActionBean")
            @Scope("prototype")
            public LoginAction loginAction() {
                return new LoginAction();
            }
        }
}

Ответ 11

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

вот так:

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

}