【问题标题】:Spring Boot starter - RestTemplateSpring Boot 启动器 - RestTemplate
【发布时间】:2021-03-22 00:16:35
【问题描述】:

我目前正在尝试编写一个 Spring Boot 启动器,该启动器将自动使用 API 网关对我们的微服务进行身份验证,并将访问令牌包含在所有传出请求的标头中(朝向网关)。
我正在创建一个 RestTemplate bean 并为其提供我们的自定义拦截器,但我的问题是,这样做会阻止其他团队(将使用此启动器)使用他们自己的 RestTemplate 配置,因为他们必须定义同一个 bean,导致多个 bean 存在。

@Bean
public RestTemplate restTemplate(){
  RestTemplate restTemplate = new RestTemplate();
  List<ClientHttpRequestInterceptor> interceptors = restTemplate.getInterceptors();
  if (interceptors.isEmpty()){
    interceptors = new ArrayList<>();
  }
  interceptors.add(clientCredentialsAuthInterceptor());
  restTemplate.setInterceptors(interceptors);
  return restTemplate;
}

是否有其他方法可以拦截所有传出请求或使 RestTemplate 进一步可配置?

【问题讨论】:

  • 理想情况下,您的项目应该使用RestTemplateBuilder 创建RestTEmplate 的实例,这反过来会自动检测所有预先注册的拦截器。您的 autp-config 唯一要做的就是为拦截器制作一个 bean。或者定义一个添加拦截器的RestTemplateCustomizer。但是,这仅在团队遵循使用 RestTemplateBuilder 创建实例的做法时才有效。

标签: java spring-boot resttemplate


【解决方案1】:

未经测试,但它可以为您提供一个起点:

// Create an interface that users of your dependency 
// can implement which provides interceptors
public interface RestTemplateAuthInterceptorProvider {

  // This interface provides interceptors, so they can add as many as they want
  List<ClientHttpRequestInterceptor> provideInterceptor();
}

import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
// define a conditional default implementation of your interceptor provider
@Bean
@ConditionalOnMissingBean(RestTemplateAuthInterceptorProvider.class)
public RestTemplateAuthInterceptorProvider restTemplateAuthInterceptorProvider() {
  return () -> ... // implement your auth interceptor and return
}

// In your actual rest template creation use method argument injection
// If other teams implement the RestTemplateAuthInterceptorProvider interface
// conditional case above will be false and your implementation will not interfere
// If they dont implement RestTemplateAuthInterceptorProvider
// your default implementation will be here
@Bean
public RestTemplate restTemplate(RestTemplateAuthInterceptorProvider provider) {
  RestTemplate restTemplate = new RestTemplate();
  List<ClientHttpRequestInterceptor> interceptors = restTemplate.getInterceptors();
  if (interceptors == null){
    interceptors = new ArrayList<>();
  }
  interceptors.addAll(provider.provideInterceptor()); // from argument 
  restTemplate.setInterceptors(interceptors);
  return restTemplate;
}

编辑: 另一种 hacky 方法是操作已经定义的 RestTemplate bean

@Component
@ConditionalOnBean(RestTemplate.class)
public class RestTemplateBeanCustomizer {

  private List<RestTemplate> restTemplateBeans;

  // This injects all restTemplate bean definitions to your bean as a list
  @Autowired
  public RestTemplateBeanCustomizer(List<RestTemplate> restTemplateBeans) {
    this.restTemplateBeans = restTemplateBeans;
  }

  @PostConstruct
  public void customizeRestTemplateBeans() {
      for (RestTemplate restTemplate : restTemplateBeans) {
        // Add your interceptors message handlers etc
        // restTemplate.set...
      }
  }
}

【讨论】:

  • 这只会允许他们定义他们的自定义拦截器,如果我是正确的。我的问题更多是关于创建 RestTemplate 本身。假设他们想向其中添加一个自定义 messageHandler,但启动器已经定义了一个没有它的 bean。我可以用@ConditionalOnMissingBean 对其进行注释,但是如果有人定义它,它就不会设置拦截器。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-02-26
  • 1970-01-01
  • 2021-06-19
  • 2016-07-27
  • 1970-01-01
  • 2019-04-28
  • 1970-01-01
相关资源
最近更新 更多