@ Scope (“原型”) bean 作用域没有创建新的 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}

Spring 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");
}
}
248195 次浏览

作用域原型意味着每次你向 spring (getBean 或者依赖注入)请求一个实例时,它都会创建一个新的实例并给出一个引用。

在您的示例中,创建了一个新的 LoginAction 实例并将其注入到 HomeController 中。如果您在另一个控制器中注入 LoginAction,您将获得一个不同的实例。

如果您希望为每个调用都有一个不同的实例——那么每次都需要调用 getBean ——那么注入到单例 bean 中是不会实现这一点的。

仅仅因为注入到控制器中的 bean 是原型范围的,并不意味着控制器是原型范围的!

使用 ApplicationContextAware将您绑定到 Spring (这可能是一个问题,也可能不是问题)。我建议传递一个 LoginActionFactory,您可以在每次需要时要求一个 LoginAction的新实例。

您的控制器还需要定义 @Scope("prototype")

像这样:

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


}

@ controller 是一个单例对象,如果将一个原型 bean 注入到一个单例类中,那么这个原型 bean 也会变成单例对象,除非你指定使用 lookup-method 属性,这个属性实际上会为你每次调用创建一个新的原型 bean 实例。

使用 request scope @Scope("request")为每个请求获取 bean,或者使用 @Scope("session")为每个会话“ user”获取 bean

正如 Nicholas Hauschild提到的,注入 Spring 上下文不是一个好主意。在您的情况下,@Scope (“ request”)足以修复它。但是假设您需要控制器方法中的几个 LoginAction实例。在这种情况下,我建议创建 Supplier 的 bean (春天4解决方案) :

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

然后将其注入控制器:

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

由于 Spring2.5有一个非常简单(和优雅)的方法来实现这一点。

您只需更改 @Scope注释的参数 proxyModevalue

通过这个技巧,您可以避免在每次需要单例 bean 中的原型时编写额外的代码或注入 ApplicationContext。

例如:

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

如果配置高于 LoginAction(在 HomeController内部) ,则始终是 原型机,即使控制器是 单身

注入到 singelton bean 中的原型 bean 的行为将类似于 singelton,直到通过 get bean 显式调用创建新实例。

context.getBean("Your Bean")

@ 组件

@ 范围(值 = “原型”)

公共课田纳西教练执行教练{

一些代码

}

默认情况下,Spring bean 是单例的 尝试将不同作用域的 bean 连接起来 这就是所谓的作用域 bean 注入问题。

解决这个问题的另一种方法是使用 @ 查找注释进行方法注入。

下面是一篇关于 将原型 bean 注入到单例实例中这个问题的多种解决方案的精彩文章。

Https://www.baeldung.com/spring-inject-prototype-bean-into-singleton

@Configuration一起上课

@Bean
@RequestScope //composed annotation for @Scope(value=...proxyMode=...)
public LoginAction requestScopedBean() {
return new LoginAction ();
}
@Controller
public class HomeController {


@Resource(name = "requestScopedBean")
private LoginAction loginAction;


//...your code here