Spring Integration中为HttpRequestExecutingMessageHandler按消息配置RestTemplate
Great question! Your current approach works, but there are cleaner, more maintainable ways to handle dynamic RestTemplate selection (or even avoid multiple RestTemplates entirely) without duplicating code from AbstractHttpRequestExecutingMessageHandler. Let's break down the best options:
Option 1: Avoid Multiple RestTemplates - Use a Dynamic Bearer Token Interceptor
If the only difference between your target APIs is the Bearer token (and not other RestTemplate configurations like timeouts or message converters), you don't need separate RestTemplates at all. Instead, use a single RestTemplate with a custom interceptor that pulls the token from message headers dynamically:
import org.springframework.http.HttpRequest; import org.springframework.http.client.ClientHttpRequestExecution; import org.springframework.http.client.ClientHttpRequestInterceptor; import org.springframework.http.client.ClientHttpResponse; import org.springframework.integration.context.MessageContextHolder; import org.springframework.messaging.Message; import java.io.IOException; public class DynamicBearerTokenInterceptor implements ClientHttpRequestInterceptor { @Override public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException { // Fetch the current message from the integration context Message<?> message = MessageContextHolder.get().getMessage(); String bearerToken = message.getHeaders().get("AUTH_BEARER_TOKEN", String.class); if (bearerToken != null) { request.getHeaders().setBearerAuth(bearerToken); } return execution.execute(request, body); } }
Configure your RestTemplate to use this interceptor:
@Bean public RestTemplate apiRestTemplate() { RestTemplate restTemplate = new RestTemplate(); restTemplate.getInterceptors().add(new DynamicBearerTokenInterceptor()); return restTemplate; }
Now you can use a standard HttpRequestExecutingMessageHandler—just pass the token in the AUTH_BEARER_TOKEN message header for each request. This is the simplest approach if token differences are your only requirement.
Option 2: Override getRestTemplate() Instead of Duplicating Code
If you truly need separate RestTemplates (e.g., for different timeouts, SSL configurations, or converter sets), you don't have to copy the entire exchange method from the parent class. The HttpRequestExecutingMessageHandler exposes a protected getRestTemplate() method that you can override to resolve the correct bean from the application context using a message header:
import org.springframework.context.ApplicationContext; import org.springframework.integration.context.MessageContextHolder; import org.springframework.integration.http.outbound.HttpRequestExecutingMessageHandler; import org.springframework.messaging.Message; import org.springframework.web.client.RestTemplate; public class DynamicRestTemplateHttpRequestHandler extends HttpRequestExecutingMessageHandler { private final ApplicationContext applicationContext; public DynamicRestTemplateHttpRequestHandler(String uri, ApplicationContext applicationContext) { super(uri); this.applicationContext = applicationContext; } @Override protected RestTemplate getRestTemplate() { // Get the current message from the integration context Message<?> currentMessage = MessageContextHolder.get().getMessage(); String restTemplateBeanName = currentMessage.getHeaders().get("REST_TEMPLATE_BEAN_NAME", String.class); // Fall back to the default RestTemplate if no header is provided if (restTemplateBeanName == null) { return super.getRestTemplate(); } // Resolve the requested RestTemplate bean return applicationContext.getBean(restTemplateBeanName, RestTemplate.class); } }
This approach keeps your code minimal and maintains compatibility with future updates to the parent class's exchange logic (since you're not duplicating that code). Just register your dynamic handler as a bean, and pass the target RestTemplate bean name in the REST_TEMPLATE_BEAN_NAME header for each request.
Why These Are Better Than Your Current Approach
- Less code duplication: Option 2 avoids copying the entire
exchangemethod, reducing maintenance overhead if Spring Integration updates the parent class logic. - Simpler architecture: Option 1 eliminates the need for multiple RestTemplates entirely if token differences are your only concern.
- More idiomatic Spring: Both approaches leverage existing Spring Integration and Spring Framework features instead of reinventing the wheel.
内容的提问来源于stack exchange,提问作者vijay

