【问题标题】:Spring boot - rest template and rest template builderSpring Boot - 休息模板和休息模板构建器
【发布时间】:2016-10-10 11:46:48
【问题描述】:

据我所知,RestTemplateBuilderRestTemplate 的某种工厂。我有几个关于使用它的问题:

  1. 在示例中,@Configuration 类中经常有这样的内容:

    @Bean
    public RestTemplate getRestClient() {
        RestTemplate restClient = new RestTemplate();
        ...
        return restClient;
    }
    

    RestTemplate 不应该在每个 @Service 类中实例化吗?如果有,如何定制?

  2. Spring 参考说RestTemplateBuilder 应该通过RestTemplateCustomizer 自定义。如何使用一个构建器管理来自多个 IP 地址的多个 URI?

  3. 如何通过RestTemplateBuilderBasicAuthentication全局添加到所有RestTemplates,这是一个好习惯吗?

感谢您的帮助。

更新

我的应用程序从不同 IP 和 url 的许多服务器调用 rest 服务 - 所以逻辑上对我来说是当我有很多 RestTemplates 时的情况。

我正在尝试为每台服务器创建一个工厂 (RestTemplateBuilder) - 比如说服务器 A、B、C。我知道如何添加基本身份验证。但是,例如,当我想要对服务器 A 进行基本身份验证而不对服务器 B 进行基本身份验证时呢?

我考虑为每台服务器设置一个RestTemplateBuilder。我不想手动执行此操作 - 我更喜欢使用 Spring 机制。

有什么帮助吗?

【问题讨论】:

  • 关于basicAuthentication - stackoverflow.com/questions/21920268/…
  • 我知道如何添加基本身份验证。我正在寻找良好的架构解决方案,将其添加为客户端请求的一部分,而不是其他部分,并且不要为每个 @Service 类手动执行此操作。

标签: java spring rest spring-mvc


【解决方案1】:
  1. 不,你不需要,通常你会有一个rest模板实例,你会传递不同的url,并且每次都相应地请求参数。

    String result = restTemplate.getForObject("http://example.com/hotels/{hotel}/bookings/{booking}", String.class, vars);
    
    Foo foo = restTemplate.getForObject(fooResourceUrl + "/1", Foo.class);
    
  2. 来自spring doc 的描述性示例,您可以向构建器添加尽可能多的定制器

    public class ProxyCustomizer implements RestTemplateCustomizer {
    
        @Override
        public void customize(RestTemplate restTemplate) {
            HttpHost proxy = new HttpHost("proxy.example.com");
            HttpClient httpClient = HttpClientBuilder.create()
                    .setRoutePlanner(new DefaultProxyRoutePlanner(proxy) {
    
                        @Override
                        public HttpHost determineProxy(HttpHost target,
                                HttpRequest request, HttpContext context)
                                        throws HttpException {
                            if (target.getHostName().equals("192.168.0.5")) {
                                return null;
                            }
                            return super.determineProxy(target, request, context);
                        }
    
                    }).build();
            restTemplate.setRequestFactory(
                    new HttpComponentsClientHttpRequestFactory(httpClient));
        }
    
    }
    

任何 RestTemplateCustomizer bean 都会自动添加到 自动配置的 RestTemplateBuilder。此外,一个新的 可以通过以下方式创建带有附加定制器的 RestTemplateBuilder 调用 additionalCustomizers(RestTemplateCustomizer…​)

@Bean
public RestTemplateBuilder restTemplateBuilder() {
   return new RestTemplateBuilder()
        .rootUri(rootUri)
        .basicAuthorization(username, password);
}

【讨论】:

    【解决方案2】:

    我的配置是这样设置的:

    @Bean
    public RestTemplateCustomizer restTemplateCustomizer() {
        return restTemplate -> {
            restTemplate.setRequestFactory(clientHttpRequestFactory());
        };
    }
    
    @Bean
    public ClientHttpRequestFactory clientHttpRequestFactory() {
        SimpleClientHttpRequestFactory clientHttpRequestFactory = new SimpleClientHttpRequestFactory();
        clientHttpRequestFactory.setConnectTimeout(connectionTimeoutMs);
        clientHttpRequestFactory.setReadTimeout(connectionTimeoutMs);
        clientHttpRequestFactory.setBufferRequestBody(false);
        return clientHttpRequestFactory;
    }
    

    每当 Spring 注入 RestTemplateBuilder 时,它都会使用此 RestTemplateCustomizer 对其进行配置以使用 ClientHttpRequestFactory。您可能需要进行一些不同的自定义,或者可能不需要在这种情况下不声明 bean。

    要添加身份验证标头,您需要知道用户名和密码,您可能要到运行时才知道。所以我创建了一个 Authenticator bean:

    @Component
    public class Authenticator {
    
        @Autowired
        private RestTemplateBuilder restTemplateBuilder;
    
        public void withAuthenticationHeader(String username, String password, Consumer<RestTemplate> doAuthenticated) {
            RestTemplate restTemplate =
                restTemplateBuilder
                    .basicAuthorization(username, password)
                    .build();
    
            try {
                doAuthenticated.accept(restTemplate);
    
            } catch (HttpClientErrorException exception) {
                // handle the exception
            }
        }
    }
    

    这使我能够以标准方式为所有请求处理身份验证失败,这正是我的应用程序所需要的。

    它被注入到其他bean中并像这样使用:

    @Autowired
    private Authenticator authenticator;
    
    public void transmit() {
        authenticator.withAuthenticationHeader(username, password, restTemplate -> 
            restTemplate.postForLocation(url, request));
    }
    

    所以你应该使用 Authenticator 而不是直接使用 RestTemple。 我找不到此类事情的任何标准模式,但这似乎有效。

    【讨论】:

      猜你喜欢
      • 2018-01-24
      • 1970-01-01
      • 1970-01-01
      • 2014-02-28
      • 1970-01-01
      • 2018-12-17
      • 2015-11-13
      • 1970-01-01
      相关资源
      最近更新 更多