Java Spring Boot - 休息模板和休息模板构建器

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/39957550/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 21:35:35  来源:igfitidea点击:

Spring boot - rest template and rest template builder

javaspringrestspring-mvc

提问by javovy

As I know the RestTemplateBuilderis some kind of factory for RestTemplate. I have a few questions about using it:

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

  1. Very often in examples there is something like this in @Configurationclass:

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

    Shouldn't RestTemplatebe instantiated per @Serviceclass ? If so, how to customize it ?

  2. Spring reference says that RestTemplateBuildershould be customized via RestTemplateCustomizer. How to manage many URI's from many IP addresses with one builder ?

  3. How to add BasicAuthenticationglobaly to all RestTemplatesvia RestTemplateBuilder, and is it a good practice?

  1. 在例子中经常有这样的事情在@Configuration课堂上:

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

    RestTemplate应该每个@Service类实例化吗?如果是这样,如何自定义它?

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

  3. 如何将BasicAuthenticationglobaly添加到 all RestTemplatesvia RestTemplateBuilder,这是一个好习惯吗?

Thanks for help.

感谢帮助。

UPDATE:

更新

My application calls rest services from many servers at different IP's and urls - so logically for me is the situation when I have many RestTemplates.

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

I'm trying to have a factory (RestTemplateBuilder) per server - let's say servers A, B, C. I know how to add a basic authentication. But what for example when I want a basic authentication for server A but not for server B ?

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

I think about having one RestTemplateBuilderper server. I don't want to do this manually - I would prefer to use Spring mechanisms.

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

Any help ?

有什么帮助吗?

回答by kuhajeyan

  1. No, you don't need to, typically you will have on rest template instance, and you would pass different url, and request parameters accordingly every time.

    String result = restTemplate.getForObject("http://example.com/hotels/{hotel}/bookings/{booking}", String.class, vars);
    
    Foo foo = restTemplate.getForObject(fooResourceUrl + "/1", Foo.class);
    
  2. A descriptive example from spring doc, you can add as many customizers to the builder

    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));
        }
    
    }
    
  1. 不,您不需要,通常您将拥有休息模板实例,并且每次都会传递不同的 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));
        }
    
    }
    

Any RestTemplateCustomizer beans will be automatically added to the auto-configured RestTemplateBuilder. Furthermore, a new RestTemplateBuilder with additional customizers can be created by calling additionalCustomizers(RestTemplateCustomizer…?)

任何 RestTemplateCustomizer bean 都将自动添加到自动配置的 RestTemplateBuilder。此外,可以通过调用 additionalCustomizers(RestTemplateCustomizer...?) 来创建一个带有额外定制器的新 RestTemplateBuilder

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

回答by whistling_marmot

I've set up my config like this:

我已经像这样设置了我的配置:

@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;
}

Whenever Spring injects a RestTemplateBuilder, it will configure it using this RestTemplateCustomizer to use the ClientHttpRequestFactory. You may need to do some different customizations, or perhaps none in which case don't declare the bean.

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

To add the authentication header, you will need to know the user name and password, which you probably won't know until run-time. So I've created an Authenticator 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
        }
    }
}

This allows me to handle authentication failures in a standard way for all requests, which is what I need in my application.

这允许我以标准方式处理所有请求的身份验证失败,这正是我在应用程序中所需要的。

It is injected into other beans and used like so:

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

@Autowired
private Authenticator authenticator;

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

So you'd use the Authenticator rather than using the RestTemple directly. I couldn't find any standard patterns for this sort of thing, but this seems to work.

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