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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-08 04:40:48  来源:igfitidea点击:

@Scope("prototype") bean scope not creating new bean

springspring-mvc

提问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.

你可以只改变PARAMSproxyModevalue中的@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();
            }
        }
}