在springboot应用程序中使用rest模板调用以@async注解的方法

pkln4tw6  于 2021-08-20  发布在  Java
关注(0)|答案(2)|浏览(489)

我对@async和rest模板调用有问题;这是我的主要应用程序类,带有一个任务执行器bean和enablesync注解

  1. @SpringBootApplication
  2. @ComponentScan({"org.***"})
  3. @EnableAspectJAutoProxy
  4. @EnableAsync
  5. @EnableAutoConfiguration(exclude={DataSourceAutoConfiguration.class,HibernateJpaAutoConfiguration.class})
  6. @EnableFeignClients(basePackages = {"org.service.feign"})
  7. public class MainApplication extends SpringBootServletInitializer {
  8. /**
  9. * <p>main.</p>
  10. *
  11. * @param args an array of {@link java.lang.String} objects.
  12. */
  13. public static void main(String[] args) {
  14. SpringApplication.run(MainApplication.class, args);
  15. }
  16. @Bean(name = "threadPoolTaskExecutor")
  17. public Executor taskExecutor() {
  18. ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
  19. executor.setCorePoolSize(5);
  20. executor.setMaxPoolSize(5);
  21. executor.setQueueCapacity(100);
  22. executor.setThreadNamePrefix(“CustomLookup-");
  23. executor.initialize();
  24. return executor;
  25. }
  26. /**
  27. * Configure.
  28. *
  29. * @param application the application
  30. * @return the spring application builder
  31. */
  32. @Override
  33. protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
  34. return application.sources(MainApplication.class);
  35. }
  36. /**
  37. * <p>requestContextListener.</p>
  38. *
  39. * @return a {@link org.springframework.web.context.request.RequestContextListener} object.
  40. */
  41. @Bean
  42. public RequestContextListener requestContextListener() {
  43. return new RequestContextListener();
  44. }
  45. }

这是我在rest控制器中调用的带有异步注解的测试服务:

  1. @Service
  2. public class TestService {
  3. @Async("threadPoolTaskExecutor")
  4. public ResponseEntity<Object> test()
  5. throws Exception{
  6. PagedRequest<SearchRequest> request = new PagedRequest<SearchRequest>();
  7. SearchRequest filters = new Request();
  8. filters.setCod(“abcdeg");
  9. request.setFilters(filters);
  10. RestTemplate restTemplate = new RestTemplate();
  11. restTemplate.setInterceptors(Collections.singletonList(new RestInterceptor())); // here I set a custom headers
  12. final HttpHeaders theJsonHeader = new HttpHeaders();
  13. theJsonHeader.setContentType(MediaType.APPLICATION_JSON);
  14. final MultiValueMap<String, Object> theMultipartRequest = new LinkedMultiValueMap<>();
  15. ObjectMapper objectMapper = new ObjectMapper();
  16. String someJsonString = objectMapper.writeValueAsString(request);
  17. theMultipartRequest.add("request", new HttpEntity<>(someJsonString, theJsonHeader));
  18. ResponseEntity<Object> response = null;
  19. final HttpEntity<PagedRequest<SearchRequest>> theHttpEntity = new HttpEntity<>(request, theJsonHeader);
  20. String path = “http://...”; //url removed for privacy
  21. response = restTemplate.postForEntity(path, theHttpEntity, Object.class);
  22. return response;
  23. }
  24. }

此服务返回rest模板上的空指针;这是stacktrace

  1. java.lang.NullPointerException: null
  2. at org.springframework.web.client.DefaultResponseErrorHandler.hasError(DefaultResponseErrorHandler.java:61) ~[spring-web-5.2.3.RELEASE.jar:5.2.3.RELEASE]
  3. at org.springframework.web.client.RestTemplate.handleResponse(RestTemplate.java:773) ~[spring-web-5.2.3.RELEASE.jar:5.2.3.RELEASE]
  4. at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:743) ~[spring-web-5.2.3.RELEASE.jar:5.2.3.RELEASE]
  5. at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:677) ~[spring-web-5.2.3.RELEASE.jar:5.2.3.RELEASE]
  6. at org.springframework.web.client.RestTemplate.postForEntity(RestTemplate.java:452) ~[spring-web-5.2.3.RELEASE.jar:5.2.3.REL

这里是我在resttemplate中添加的restintercept代码

  1. public class RestInterceptor implements ClientHttpRequestInterceptor {
  2. @Override
  3. public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException {
  4. ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
  5. if (requestAttributes == null)
  6. return null;
  7. HttpServletRequest req = requestAttributes.getRequest();
  8. if (req == null || req.getHeader(PrevConstants.USER_KEY)==null || req.getHeader(PrevConstants.JWT_HEADER_NAME)==null)
  9. return null;
  10. String userKey = req.getHeader(PrevConstants.USER_KEY);
  11. String jwt = req.getHeader(PrevConstants.JWT_HEADER_NAME);
  12. if (jwt == null) {
  13. jwt = "custom jwt";
  14. }
  15. else if ( !jwt.startsWith("Bearer")) { jwt = "Bearer " + jwt; }
  16. request.getHeaders().set(PrevConstants.USER_KEY, userKey);
  17. request.getHeaders().set(PrevConstants.JWT_HEADER_NAME, jwt);
  18. ClientHttpResponse response = execution.execute(request, body);
  19. return response;
  20. }
  21. }

但是如果我删除,@enablesync和@async,那么简单的rest模板就可以完美地工作。有什么问题吗?我不知道。谢谢你的回复

fnx2tebb

fnx2tebb1#

RequestContextHolder 保存当前线程正在处理的请求的上下文。当你使用 @Async 您的拦截器在处理请求的线程的不同线程上被调用。因此, RequestContextHolder.getRequestAttributes() 返回 null 然后你的拦截器返回一个 null 答复。遵守合同 ClientHttpRequestInterceptor#intercept 它必须返回一个非空值,因此 null 响应导致失败。
如果你想用 @Async ,您必须检索 RequestAttributes 在rest控制器中,然后将它们传递到 TestService 作为 test 方法。然后,您可以创建 RestInterceptor 使用属性,而不是使用 RequestContextHolder 要访问它们:

  1. @Async("threadPoolTaskExecutor")
  2. public ResponseEntity<Object> test(RequestAttributes requestAttributes) throws Exception {
  3. // …
  4. RestTemplate restTemplate = new RestTemplate();
  5. restTemplate.setInterceptors(Collections.singletonList(new RestInterceptor(requestAttributes)));
  6. // …
  7. }
rt4zxlrg

rt4zxlrg2#

@andy,我已经直接从我的rest控制器传递了第一个requestattributes和第二个片刻的httpservletrequest,但结果是相同的,nullpointer。你有我能看到的剪报吗?

  1. @Async("threadPoolTaskExecutor")
  2. public ResponseEntity<Object> test(HttpServletRequest req) throws Exception {
  3. // …
  4. RestTemplate restTemplate = new RestTemplate();
  5. restTemplate.setInterceptors(Collections.singletonList(new RestInterceptor(req)));
  6. // …
  7. }

  1. public class RestInterceptor implements ClientHttpRequestInterceptor {
  2. private HttpServletRequest req;
  3. public RestInterceptor(HttpServletRequest req){
  4. this.req=req;
  5. }
  6. @Override
  7. public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException {
  8. HttpServletRequest req = this.req;
  9. if (req == null || req.getHeader(PrevConstants.USER_KEY)==null || req.getHeader(PrevConstants.JWT_HEADER_NAME)==null)
  10. return null;
  11. String userKey = req.getHeader(PrevConstants.USER_KEY);
  12. String jwt = req.getHeader(PrevConstants.JWT_HEADER_NAME);
  13. if (jwt == null) {
  14. jwt = "custom token";
  15. }
  16. else if ( !jwt.startsWith("Bearer")) { jwt = "Bearer " + jwt; }
  17. request.getHeaders().set(PrevConstants.USER_KEY, userKey);
  18. request.getHeaders().set(PrevConstants.JWT_HEADER_NAME, jwt);
  19. ClientHttpResponse response = execution.execute(request, body);
  20. return response;
  21. }
展开查看全部

相关问题