我想在我的控制器中使用带注释的原型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}
Spring config.xml
启用了组件扫描:
<context:annotation-config />
<context:component-scan base-package="com.springheat" />
<mvc:annotation-driven />
我每次都会增加计数。无法弄清楚我哪里出错了!
更新
作为suggested by @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");
}
}
答案 0 :(得分:133)
范围原型意味着每次向实例请求spring(getBean或依赖注入)时,它都会创建一个新实例并提供对它的引用。
在您的示例中,将创建一个新的LoginAction实例并将其注入HomeController。如果你有另一个控制器注入LoginAction,你会得到一个不同的实例。
如果你想为每个调用设置一个不同的实例 - 那么你每次都需要调用getBean - 注入单例bean将无法实现。
答案 1 :(得分:12)
仅仅因为注入控制器的bean是原型范围的并不意味着控制器是!
答案 2 :(得分:12)
自Spring 2.5 以来,我们可以轻松(优雅)地实现这一目标。
您只需更改proxyMode
注释的参数value
和@Scope
即可。
使用此技巧,您可以避免每次在单例bean中需要原型时编写额外的代码或注入ApplicationContext。
示例:
@Service
@Scope(value="prototype", proxyMode=ScopedProxyMode.TARGET_CLASS)
public class LoginAction {}
上面的配置LoginAction
(内部HomeController
)始终是原型,即使控制器是单身。
答案 3 :(得分:9)
@controller是一个单例对象,如果将一个原型bean注入一个单独的类,那么原型bean也会变成单例,除非你指定使用lookup-method属性,它实际上为你做的每个调用创建一个新的prototype bean实例。
答案 4 :(得分:4)
如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;
答案 5 :(得分:3)
使用ApplicationContextAware
将你绑定到Spring(这可能是也可能不是问题)。我建议传递LoginActionFactory
,您可以在每次需要时提出LoginAction
的新实例。
答案 6 :(得分:3)
使用请求范围@Scope("request")
为每个请求获取bean,或@Scope("session")
为每个会话获取bean&#39;用户&#39;
答案 7 :(得分:0)
注入到singelton bean中的原型bean的行为类似于singelton,直到l get bean明确要求创建新实例为止。
context.getBean("Your Bean")
答案 8 :(得分:0)
@Component
@Scope(value =“ prototype”)
公共类TennisCoach实施教练{
//一些代码
}
答案 9 :(得分:0)
您可以像这样在控制器内部创建静态类:
@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();
}
}
}
答案 10 :(得分:0)
默认情况下,Spring bean是单例。当我们出现问题时 尝试连接不同范围的咖啡豆。例如,原型豆 成一个单身。这就是范围豆注入问题。
解决问题的另一种方法是使用带有@Lookup批注的方法注入。
这是一篇关于将原型bean注入具有多个解决方案的单例实例的好文章。
https://www.baeldung.com/spring-inject-prototype-bean-into-singleton
答案 11 :(得分:-8)
您的控制器还需要@Scope(“原型”)defind
像这样:@Controller
@Scope("prototype")
public class HomeController {
.....
.....
.....
}