spring @Scope("prototype") bean 作用域不创建新 bean
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/7621920/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
@Scope("prototype") bean scope not creating new bean
提问by tintin
I want to use a annotated prototype bean in my controller. But spring is creating a singleton bean instead. Here is the code for that:
我想在我的控制器中使用一个带注释的原型 bean。但是 spring 正在创建一个单例 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 code:
控制器代码:
@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;
}
}
Velocity template:
速度模板:
LoginAction counter: ${loginAction.str}
Spring config.xmlhas component scanning enabled:
Springconfig.xml启用了组件扫描:
<context:annotation-config />
<context:component-scan base-package="com.springheat" />
<mvc:annotation-driven />
I'm getting an incremented count each time. Can't figure out where am I going wrong!
我每次都得到一个递增的计数。想不通我哪里错了!
Update
更新
As suggested by @gkamal, I made HomeControllerwebApplicationContext-aware and it solved the problem.
正如@gkamal所建议的那样,我做了 -awareHomeControllerwebApplicationContext并解决了问题。
updated code:
更新代码:
@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");
}
}
回答by gkamal
Scope prototype means that every time you ask spring (getBean or dependency injection) for an instance it will create a new instance and give a reference to that.
范围原型意味着每次您向 spring(getBean 或依赖注入)请求实例时,它都会创建一个新实例并提供对该实例的引用。
In your example a new instance of LoginAction is created and injected into your HomeController . If you have another controller into which you inject LoginAction you will get a different instance.
在您的示例中,一个新的 LoginAction 实例被创建并注入到您的 HomeController 中。如果您有另一个控制器将 LoginAction 注入其中,您将获得一个不同的实例。
If you want a different instance for each call - then you need to call getBean each time - injecting into a singleton bean will not achieve that.
如果您希望每次调用都有一个不同的实例 - 那么您每次都需要调用 getBean - 注入单例 bean 将无法实现这一点。
回答by db80
Since Spring 2.5there's a very easy (and elegant) way to achieve that.
从 Spring 2.5 开始,有一种非常简单(且优雅)的方法可以实现这一目标。
You can just change the params proxyModeand valueof the @Scopeannotation.
你可以只改变PARAMSproxyMode和value中的@Scope注释。
With this trick you can avoid to write extra code or to inject the ApplicationContext every time that you need a prototype inside a singleton bean.
使用这个技巧,您可以避免每次在单例 bean 中需要原型时编写额外的代码或注入 ApplicationContext。
Example:
例子:
@Service
@Scope(value="prototype", proxyMode=ScopedProxyMode.TARGET_CLASS)
public class LoginAction {}
With the config above LoginAction(inside HomeController) is always a prototypeeven though the controller is a singleton.
上面的配置LoginAction(内部HomeController)总是一个原型,即使控制器是一个单例。
回答by Dave Newton
Just because the bean injected into the controller is prototype-scoped doesn't mean the controller is!
仅仅因为注入控制器的 bean 是原型范围的并不意味着控制器是!
回答by kartheek
@controller is a singleton object, and if inject a prototype bean to a singleton class will make the prototype bean also as singleton unless u specify using lookup-method property which actually create a new instance of prototype bean for every call you make.
@controller 是一个单例对象,如果将原型 bean 注入单例类将使原型 bean 也成为单例对象,除非您指定使用 lookup-method 属性,该属性实际上为您进行的每次调用创建一个新的原型 bean 实例。
回答by Igor Rybak
As mentioned by nicholas.hauschildinjecting Spring context is not a good idea. In your case, @Scope("request") is enough to fix it. But let say you need several instances of LoginActionin controller method. In this case, I would recommend to create the bean of Supplier (Spring 4solution):
正如nicholas.hauschild所提到的,注入 Spring 上下文不是一个好主意。在您的情况下,@Scope("request") 足以修复它。但是假设您需要几个LoginActionin 控制器方法的实例。在这种情况下,我建议创建供应商的 bean(Spring 4解决方案):
@Bean
public Supplier<LoginAction> loginActionSupplier(LoginAction loginAction){
return () -> loginAction;
}
Then inject it into controller:
然后将其注入控制器:
@Controller
public class HomeController {
@Autowired
private Supplier<LoginAction> loginActionSupplier;
回答by Bassem Reda Zohdy
use request scope @Scope("request")to get bean for each request, or @Scope("session")to get bean for each session 'user'
使用请求范围@Scope("request")为每个请求获取 bean,或者@Scope("session")为每个会话“用户”获取 bean
回答by nicholas.hauschild
Using ApplicationContextAwareis tying you to Spring (which may or may not be an issue). I would recommend passing in a LoginActionFactory, which you can ask for a new instance of a LoginActioneach time you need one.
使用ApplicationContextAware将您与 Spring 捆绑在一起(这可能是也可能不是问题)。我建议传入 a LoginActionFactory,您可以在LoginAction每次需要时请求 a 的新实例。
回答by Ujjwal Choudhari
A protoype bean injected inside a singelton bean will behave like singelton untill expilictly called for creating a new instance by get bean.
注入到单个 bean 中的原型 bean 将表现得像单个 bean,直到通过 get bean 显式调用创建新实例。
context.getBean("Your Bean")
回答by Rakesh Singh Balhara
@Component
@成分
@Scope(value="prototype")
@Scope(value="原型")
public class TennisCoach implements Coach {
公共类 TennisCoach 实现 Coach {
// some code
// 一些代码
}
}
回答by Jacob
You can create static class inside your controller like this :
您可以像这样在控制器中创建静态类:
@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();
}
}
}

