【问题标题】:Difference between creating new instance and using scope prototype annotation in Spring在 Spring 中创建新实例和使用范围原型注释之间的区别
【发布时间】:2017-09-27 12:24:07
【问题描述】:

我的应用程序正在监听一个交换(使用rabbitMQ),期望接收一些 API 数据,然后应该将其重定向到相关位置。

我使用rxJava 订阅这些更改,目的是打开一个新线程并通过每次创建RestClient 发送请求 -> 它将接收数据,解析它,发送它并然后将响应发送回队列。

我的问题是我希望每次都创建一个新的 RestClient 实例。想过使用 Springs Scope 注释:@Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE),但似乎无法理解如何使用它,如果我每次使用 new RestClient 会有什么区别。

您能解释一下使用getBean 相对于使用new 的优势吗?

代码如下:

class MyManager {

   @Autowired
   private WebApplicationContext context;
    ....
    ...
    ...

    @PostConstruct
    myListener.subscribeOn(Schedulers.computation()).subscribe(this::handleApiRequest);


    private void  handleApiRequest(ApiData apiData){

    // Option 1:
    RestClient client = new RestClient();
    client.handleApiRequest(apiData);

    //Option 2:
    // use somehow the prototype?
    RestClient x = (RestClient)context.getBean("restTest")..
    }
}



 @Service
 //@Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE) //NEEDED??
class RestClient {
 private String server;
  private RestTemplate rest;
  private HttpHeaders headers;
  ResponseEntity<String> responseEntity;

  @PostConstruct
  private void updateHeaders() {
    headers.add(Utils.CONTENT_TYPE, Utils.APPLICATION_JSON);
    headers.add(Utils.ACCEPT, Utils.PREFIX_ALL);
  }


  public void handleApiRequest(ApiData apiRequest) {
    sendRequest(apiRequest); //implemented
    sendResponse(); //implemented
  }


}


  @Bean(name = "restTest")
  @Scope("prototype")
  public RestClient getRestTemplate() {
    return new RestClient();
  }

【问题讨论】:

    标签: java spring spring-mvc annotations rx-java2


    【解决方案1】:

    首先,resttemplate 是thread-safe。不要根据请求或使用 new 关键字(构造函数)实例化它,这是一个糟糕的设计。因为你在这里注释掉了@Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE);默认情况下,spring 将创建一个 RestClient 的单例 bean,无论您在哪里自动装配,您都将获得相同的 RestClient 实例;所以你做对了。

    @Service
     //@Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE) //NEEDED??
    class RestClient {
    

    不过我有一个问题,在 RestClient 中,你在哪里实例化 private RestTemplate rest; 我在你发布的代码中没有看到

    如果您按照建议从原型范围转移到单例范围,则可以使用@Autowired RestClient restClient;

    而不是

    @Autowired private WebApplicationContext context;
    RestClient x = (RestClient)context.getBean("restTest")
    

    样板文件更少。

    【讨论】:

    • 谢谢!我阅读了更多内容,删除了原型并自动装配了 RestClient
    • 抱歉,这样做了 :) 非常有帮助
    【解决方案2】:

    当你使用context.getBean时,返回的实例是一个Spring bean,spring会处理依赖注入、配置、生命周期回调...。当您使用new 创建它时,这些都不会发生。在您给出的示例中,@PostConstruct 方法只有在您使用 context.getBean 时才会被调用。

    【讨论】:

      【解决方案3】:

      当您使用 context.getBean() 返回的任何 bean 时,该 bean 的生命周期将由 Spring 处理。

      但是如果你用新的实例初始化 bean,你就要负责对象的创建和它的生命周期。 (因此,该类中的 @PostConstruct 和其他 spring 注释将毫无意义。)并且该 bean 中的任何依赖项都不会被注入。

      【讨论】:

        猜你喜欢
        • 2012-04-12
        • 1970-01-01
        • 2023-03-19
        • 2013-06-14
        • 1970-01-01
        • 2012-03-28
        • 2012-09-13
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多