如何从另一个线程(不是接收请求的线程)访问请求属性? 我有一个多线程方案,其中有一个ClientHttpRequestInterceptor,它正在执行某种魔术来处理传出的请求标头(从传入的请求标头转发值),并且该过程需要并行完成。 我当前的问题是当我声明将传入的标头存储为Bean的对象时(scope = RequestScope)Spring给了我这样的错误:
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'scopedTarget.headersHolder': Scope 'request' is not active for the current thread; consider defining a scoped proxy for this bean if you intend to refer to it from a singleton; nested exception is java.lang.IllegalStateException: No thread-bound request found: Are you referring to request attributes outside of an actual web request, or processing a request outside of the originally receiving thread? If you are actually operating within a web request and still receive this message, your code is probably running outside of DispatcherServlet/DispatcherPortlet: In this case, use RequestContextListener or RequestContextFilter to expose the current request.
这是我提供给Spring的配置:
@Configuration
public class WebMvcConfiguration implements WebMvcConfigurer {
private static final String REQUEST_SCOPE = "request";
@Bean
@RequestScope
public HeadersHolder headersHolder() {
logger.info("Creating new HeadersHolder instance.");
return new HeadersHolder();
}
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new HeadersInterceptor() {
@Override
public HeadersHolder getHeadersHolder() {
return headersHolder();
}
});
}
@Bean
@RequestScope
public ClientHttpRequestInterceptor headersClientInterceptor() {
return new RequestInterceptor() {
@Override
protected HeadersHolder getHeadersHolder() {
return headersHolder();
}
};
}
private RestTemplateBuilder builder() {
logger.info("Providing custom Rest Template Builder with custom Rest Template customizer");
RestTemplateBuilder builder = new RestTemplateBuilder();
return builder.messageConverters(new RestTemplate().getMessageConverters());
}
@Profile("!test")
@Bean
@LoadBalanced
public RestTemplate loadBalancedRestTemplate() {
logger.info("Providing custom load balanced Rest Template");
return builder()
.setConnectTimeout(20000)
.setReadTimeout(20000)
.interceptors(headersClientInterceptor())
.build();
}
@Profile("test")
@Bean
@DependsOn(value = {"restTemplateBuilder"})
public RestTemplate normalRestTemplate() {
logger.info("Providing custom NOT load balanced Rest Template");
return builder()
.interceptors(headersClientInterceptor())
.build();
}
}
这是标题拦截器:
public abstract class HeadersInterceptor extends HandlerInterceptorAdapter {
public abstract HeadersHolder getHeadersHolder();
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
getHeadersHolder().readFrom(request);
return true;
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
getHeadersHolder().writeTo(response);
getHeadersHolder().clear();
}
}
这是ClientHttpRequestInterceptor:
public abstract class RequestInterceptor implements ClientHttpRequestInterceptor {
protected abstract HeadersHolder getHeadersHolder();
@Override
public ClientHttpResponse intercept(HttpRequest clientRequest, byte[] body, ClientHttpRequestExecution execution) throws IOException {
HeadersHolder headersHolder = getHeadersHolder();
/* ... here I do modify the headers for the outcoming request ...
* ... based on some values that are in the incoming request.
*/
return execution.execute(clientRequest, body);
}
}
我将这个RestTemplate实例注入到@Service(单个实例)中,该服务并行调用REST API客户端包装(使用RestTemplate实例的包装)。