@Scope(“prototype”)bean范围没有创建新bean

时间:2011-10-01 17:53:18

标签: spring spring-mvc

我想在我的控制器中使用带注释的原型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");
    }
}

12 个答案:

答案 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 { 
 .....
 .....
 .....

}