对于rest接口,使用了从控制器返回的Spring + RxJava + DeferredResult。
我正在考虑在端点中添加Hateoas支持。自然的选择是春天的Hateoas。问题是Spring在异步/多线程环境中无法工作,因为它使用ThreadLocal。
有什么办法可以解决这个限制吗?我不这么认为,但也许有人有任何建议。
是否有人使用其他API将Hateoas支持添加到其他端点?
谢谢。
发布于 2015-11-09 15:12:12
因此,我使用的解决方案是关闭请求属性,然后将它们作为lift操作符的一部分应用
public class RequestContextStashOperator<T> implements Observable.Operator<T, T> {
private final RequestAttributes attributes;
/**
* Spring hateoas requires the request context to be set but observables may happen on other threads
* This operator will reapply the context of the constructing thread on the execution thread of the subscriber
*/
public RequestContextStashOperator() {
attributes = RequestContextHolder.currentRequestAttributes();
}
@Override
public Subscriber<? super T> call(Subscriber<? super T> subscriber) {
return new Subscriber<T>() {
@Override
public void onCompleted() {
subscriber.onCompleted();
}
@Override
public void onError(Throwable e) {
subscriber.onError(e);
}
@Override
public void onNext(T t) {
RequestContextHolder.setRequestAttributes(attributes);
subscriber.onNext(t);
}
};
}
}然后你可以用在一个可以观察到的
lift(new RequestContextStashOperator<>())只要对象是在与请求相同的线程中创建的。然后,您可以在可观察到的链中使用一个映射,将您的对象映射为一个资源,并在其中添加仇恨链接。
发布于 2015-10-28 14:31:54
所以答案有点晚了,但可能有人会发现它有用。关于ThreadLocal,您是正确的--如果您在不同的线程中生成仇恨链接,那么它会在异常情况下失败。我找到了一些解决办法:
@RequestMapping(path = "/{id}", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
DeferredResult<ResponseEntity<ProductResource>> example(@PathVariable("id") final String productId, final HttpServletRequest request) {
final DeferredResult<ResponseEntity<ProductResource>> deferredResult = new DeferredResult<>();
request.setAttribute(WebUtils.INCLUDE_CONTEXT_PATH_ATTRIBUTE, request.getContextPath());
final RequestAttributes requestAttributes = new ServletRequestAttributes(request);
productByIdQuery.byId(UUID.fromString(productId)).subscribe(productEntity -> {
RequestContextHolder.setRequestAttributes(requestAttributes);
deferredResult.setResult(result, HttpStatus.OK))
}, deferredResult::setErrorResult);
return deferredResult;
}因此,正如您所看到的,我保存了RequestAttributes,以便稍后在回调中设置它们。这仅仅解决了问题的一部分-您将得到另一个异常,因为您将失去contextPath属性。为了避免这种情况,显式地保存它:
request.setAttribute(WebUtils.INCLUDE_CONTEXT_PATH_ATTRIBUTE, request.getContextPath());在这些变化之后,一切看起来都正常,当然看起来很混乱。我希望有人能提供更优雅的解决方案。
https://stackoverflow.com/questions/28540421
复制相似问题