Ryan Pridgeon
Ryan Pridgeon

Reputation: 63

Propagate Spring RequestAttributes (RequestContextHolder) to Feign configuration beans?

I'm using a Feign configuration class, declared using the annotations like so;

@FeignClient(name = "${earfsdf}", configuration = FeignConf.class)

FeignConf in this case is not a Spring @Configuration, it's purely scoped for this Feign client using the above annotation. In the FeignConf, I'm declaring a RequestInterceptor bean;

@Bean
public RequestInterceptor requestInterceptor() {

This gets picked up by Feign correctly, and it's called when I make the request on the Feign client.

However, I want this RequestInterceptor bean to be able to access the Spring "RequestAttributes", which I'm trying to obtain using Spring's RequestContextHolder.getRequestAttributes()

It seems that when I call this from within the RequestInterceptor, it returns null. Is there some way I can propagate the RequestAttributes into the Feign RequestInterceptor to be available?

Thanks!

Upvotes: 0

Views: 1113

Answers (1)

Ryan Pridgeon
Ryan Pridgeon

Reputation: 63

So it turns out the answer to this is to use a HystrixCallableWrapper, which allows you to wrap a task going through Hystrix (which I am using with Feign)

Hystrix creates a new thread for the Feign call. The callable wrapper is called on the parent thread, so you can take all of the context you need, pass it into a new callable, and then load the context inside the callable which is executed on the new thread.

public class ContextAwareCallableWrapper implements HystrixCallableWrapper {

  @Override
  public <T> Callable<T> wrapCallable(Callable<T> callable) {

    Context context = loadContextFromThisThread();

    return new ContextAwareCallable<>(callable, context);
  }

  public static class ContextAwareCallable<T> implements Callable<T> {

    private final Callable<T> callable;
    private Context context;

    ContextAwareCallable(Callable<T> callable, Context context) {
      this.callable = callable;
      this.context = context;
    }

    @Override
    public T call() throws Exception {

      try {
        loadContextIntoNewThread(context);
        return callable.call();
      } finally {
        resetContext();
      }
    }
  }
}

Upvotes: 1

Related Questions