在 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")
减少样板文件。
我的应用程序正在侦听交换(使用 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")
减少样板文件。