从RequestContext或类似方法访问StreamListener头

时间:2019-06-05 12:11:05

标签: java spring spring-boot apache-kafka-streams requestcontext

我有一项服务,可以调用许多其他服务。这是在控制器类中使用@StreamListener从Kafka主题读取的。出于可追溯性的目的,还必须将来自Kafka消息的相同标头(原始请求ID)转发给所有其他服务

传统上,使用@PostMapping("/path")GetMapping会生成一个请求上下文,并且可以使用RequestContextHolder.currentRequestAttributes()从任何地方访问标头,而我只会传递HttpHeaders每当我需要拨打外部电话时,都会将对象变成RequestEntity

但是在StreamListener中,不会生成任何请求上下文,并且尝试访问RequestContextHolder会导致异常

这是我尝试执行的操作的一个示例,导致出现异常:

public class Controller {
  @Autowired Service1 service1
  @Autowired Service2 service2

  @StreamListener("stream")
  public void processMessage(Model model) {
    service1.execute(model);
    service2.execute(model);
  }
}

public class Service {
  RestTemplate restTemplate;

  public void execute(Model model){
    // Do some stuff

    HttpHeaders httpHeaders = RequestContextHolder.currentRequestAttributes().someCodeToGetHttpHeaders();
    HttpEntity<Model> request = new HttpEntity(model, httpHeaders);
    restTemplate.exchange(url, HttpMethod.POST, request, String.class);
  }
}

我当前的解决方法是将StreamListener更改为PostMapping,并使用另一个PostMapping进行调用,以便可以生成请求上下文。另一种选择是使用ThreadLocal,但看起来却很简陋

我知道使用@Headers MessageHeaders批注来访问流标头,但是,如果不将标头传递给每个服务,就很难访问它,并且会影响许多单元测试。

理想情况下,我需要一种方法来创建自己的请求上下文(或任何适当的术语),以放置一个存储请求范围对象(HttpHeader)的位置,或者通过另一种线程安全的方式来传递请求标头向下堆栈,而不向service.execute

添加请求参数

1 个答案:

答案 0 :(得分:0)

我已经找到了解决方案,并将其留给其他试图实现类似目标的人

如果您的目标是通过REST控制器和Stream侦听器端对端转发一堆标头,则可能要考虑使用Spring Cloud Sleuth

通过maven或gradle配置将其添加到您的项目中:

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-sleuth</artifactId>
</dependency>

具体地说,在Spring Cloud Sleuth中,有一项功能可以通过在application.properties中设置属性spring.sleuth.propagation-keys来转发标题或“行李”。这些键值对会在整个跟踪过程中保持不变,包括任何下游http或stream调用,这些调用也实现了相同的传播键。

如果需要在代码级别访问这些字段,则可以使用ExtraFieldPropagation静态函数来获取和设置它们:

ExtraFieldPropagation.set("country-code", "FO"); // Set
String countryCode = ExtraFieldPropagation.get("country-code"); // Get

请注意,ExtraFieldPropagation设置程序无法设置已定义的spring.sleuth.propagation-keys中不存在的属性,因此不会接受任意键

您可以在documentation上阅读以获取更多信息