我在多线程环境中面临restTemplate 问题。我正在使用 url http://localhost:8080/search 调用 Rest api,它是一个 post 请求,我传递一个具有搜索参数的对象。我用它来搜索用户、部门等。这会返回一个具有这样结构的响应搜索对象,第一个用于用户,第二个用于部门
{"totalCount":2,"startIndex":0,"endIndex":1,"resultList":[{"username":"a", userid:"1}, {"username":"b", userid:"2"}, {"username":"c", userid:"3"} ]}
{"totalCount":2,"startIndex":0,"endIndex":1,"resultList":[{"deptname":"a", deptid:"1"}, {"deptid":"b", deptid:"2"} ]}
有时,如果 api 很慢,响应返回会被覆盖,例如对于部门和用户,将返回相同的响应,如
{{"totalCount":2,"startIndex":0,"endIndex":1,"resultList":[{"username":"a", userid:"1}, {"username":"b", userid:"2"}, {"username":"c", userid:"3"} ]}
我正在自动装配restTemplate 的单个实例。我还尝试为每个请求创建一个新的restTemplate 实例,但这没有帮助。
我正在自动装配restTemplate 的单个实例。我还尝试为每个请求创建一个新的restTemplate 实例,但这没有帮助。
------------更新-------------
控制器代码类似于:
@RequestMapping("search")
public @ResponseBody Map<String, Object> search(String type,
String start, Integer count) {
Map<String, Object> responseJson = new HashMap<>();
Criteria criteria = new Criteria();
criteria.setCount(count);
criteria.setStartCount(start);
criteria.setType(type);
Result<?> result;
String url = "http://localhost:8080/search";
HttpEntity<Object> httpEntity = new HttpEntity<>();
ResponseEntity<? extends Object> response = restTemplate.exchange(url, HttpMethod.POST, httpEntity, Result.class);
if (response.getStatusCode() == HttpStatus.OK) {
responseJson = (Result<?>) response.getBody();
}
return responseJson;
}
我还检查了 API 代码,发现当我收到覆盖的响应时,他们正在发送正确的响应。所以看起来请求参数传递正确并且 API 发送的响应是正确的。
如果我没记错的话,RestTemplate 的交换方法不是线程安全的。这就是 Spring 不将 RestTemplate 创建为 bean 的原因。 (RestTemplate线程安全问题)
自动装配并使用 RestTemplateBuilder 来获取新的 RestTemplate。它会解决你的问题。
@Autowired RestTemplateBuilder restTemplateBuilder;
@RequestMapping("search")
public @ResponseBody Map<String, Object> search(String type,
String start, Integer count) {
Map<String, Object> responseJson = new HashMap<>();
Criteria criteria = new Criteria();
criteria.setCount(count);
criteria.setStartCount(start);
criteria.setType(type);
Result<?> result;
String url = "http://localhost:8080/search";
HttpEntity<Object> httpEntity = new HttpEntity<>();
RestTemplate restTemplate = restTemplateBuilder.build(); // <-- here here
ResponseEntity<? extends Object> response = restTemplate.exchange(url, HttpMethod.POST, httpEntity, Result.class);
if (response.getStatusCode() == HttpStatus.OK) {
responseJson = (Result<?>) response.getBody();
}
return responseJson;
}
RestTemplate
不是线程安全的类,因此在多线程环境中使用它会陷入奇怪的情况。为了避免这种情况,您只需使用 new
运算符即可在每个请求上创建一个实例:
RestTemplate restTemplate = new RestTemplate();