将Springbean范围从请求更改为singleton的影响



我的代码中有以下类,可以说它只是标准RestTemplate的包装器。因此,每当我们必须发出外部请求而不是使用RestTemplate时,我们就会使用autowire自定义MyRestTemplate

@Service
@Scope(scopeName = "request", proxyMode = ScopedProxyMode.TARGET_CLASS)
public class MyRestTemplateImpl implements MyRestTemplate {
private final RestTemplate restTemplate;
private Logger logger = LogManager.getLogger(MyRestTemplateImpl.class);
@Autowired
public MyRestTemplateImpl(RestTemplate restTemplate) {
this.restTemplate = restTemplate;
}

@Override
public <T> ResponseEntity<T> exchange(String url, HttpMethod method, HttpEntity<?> requestEntity, Class<T> responseType, Object... uriVariables) throws RestClientException {
ResponseEntity responseEntity = restTemplate.exchange(url, method, requestEntity, responseType, uriVariables);
return responseEntity;
}
}

现在的问题是,我正在进行一些Asyncrest调用,它反过来调用MyRestTemplate来进行外部rest请求。但它失败了,给出了以下错误:

创建名为"scopedTarget.myRestTemplateImpl"的bean时出错:当前线程的作用域"request"未处于活动状态;考虑如果您打算引用该bean,则为其定义一个作用域代理来自单个

我理解这是因为为Async操作派生了一个新线程,并且作用域request对该子线程无效。它可以通过使用How to enable request scope in async task executor中非常好的解决方案来解决,但是,我现在不想去做它,因为这种异步操作并不常见,而且我有一些时间限制。

所以,我的主要问题是,如果我把MyRestTemplateImpl作为singleton,一切都很好,我没有遇到任何这样的问题。但是有许多方法将MyRestTemplateImpl用于外部请求,并且应用程序上的流量也很重。

将其从Request更改为Singleton是否会造成任何不利影响,如速度慢、比赛条件或任何我不知道或目前尚未遇到的有害影响?

如果是的话,除了作用域之间的基本区别之外,如果你能给出适当的解释,那就太好了,因为在我现在编码的时候,它会在作用域bean时给我更好的推理。如果没有,为什么?

我知道每个请求都会创建一个新的bean,但请用小例子解释request作用域的实际用例是什么?

如果您的自定义RestTemplate看起来与您在示例代码中放置的完全一样,那么它的效用为零——您可以只使用标准RestTemplate。此外,由于您将(可能(非请求范围的RestTemplate传递给构造函数,它甚至没有做您认为它正在做的事情。如果你真的希望它是请求范围的和自动代理的,你可以得到同样的效果,而不需要对它进行子类化。例如:

@Configuration
class RestTemplateConfig {
@Bean
@Scope(scopeName = "request", proxyMode = ScopedProxyMode.TARGET_CLASS)
RestTemplate restTemplate() {
return new RestTemplate();
}
}

还要注意的是,@Service刻板印象是有争议的不准确,因为我不认为RestTemplate是一种服务。这并不重要,但将其定型为@Component可能更准确。

如果您的RestTemplate实际上添加了额外的功能,但为了简洁起见,您省略了它,那么答案是"这取决于"。一般来说,单例作用域总是正确的答案。

请求范围适用于需要Springbean具有仅与当前请求相关的数据的情况。我建议应该避免使用这种代码,但有时它很有用。例如,您可能有一个对象用于收集单个请求的统计信息-调用了多少个方法,每个方法需要多长时间才能完成,等等。您不想在所有请求中重复使用它,所以您可以将其设置为请求范围,并为每个请求重新创建它。

如果您的RestTemplate没有任何特定于请求的状态,那么每次使用请求范围创建一个新状态是没有意义的。例如,每次都可以用不同的参数反复调用exchange()——在调用exchange()时不需要创建新的RestTemplate

根据经验,您通常希望避免单例作用域以外的任何操作。您可能会遇到一些其他作用域有用的奇怪情况,但应该仔细检查它们,因为很少需要其他作用域。

最新更新