在 Spring 中创建新实例和使用作用域原型注释之间的区别

Difference between creating new instance and using scope prototype annotation in Spring

我的应用程序正在侦听交换(使用 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();
  }

当您使用 context.getBean 时,返回的实例是一个 Spring bean,spring 处理依赖注入、配置、生命周期回调...。当您使用 new none 创建它时,就会发生这种情况。在您提供的示例中,仅当您使用 context.getBean.

时才会调用 @PostConstruct 方法

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

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

首先,resttemplate是thread-safe。不要根据请求或使用 new 关键字(Constructor)实例化它,这是一个糟糕的设计。因为你在这里注释掉了@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")

减少样板文件。