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

时间:2017-09-27 12:24:07

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

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

3 个答案:

答案 0 :(得分:2)

首先,resttemplate是thread-safe。不要根据请求或使用新关键字(构造函数)对其进行实例化,这是一个糟糕的设计。因为你在这里评论了@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")

较少的样板。

答案 1 :(得分:1)

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

答案 2 :(得分:1)

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

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