Waktu Istirahat Musim Semi Template

125

Saya ingin menyetel waktu tunggu koneksi untuk layanan istirahat yang digunakan oleh aplikasi web saya. Saya menggunakan Spring's RestTemplate untuk berbicara dengan layanan saya. Saya telah melakukan beberapa penelitian dan saya telah menemukan dan menggunakan xml di bawah ini (dalam aplikasi saya xml) yang saya yakini dimaksudkan untuk menyetel batas waktu. Saya menggunakan Spring 3.0.

Saya juga melihat masalah yang sama di sini Konfigurasi waktu tunggu untuk layanan web musim semi dengan RestTemplate tetapi solusinya tampaknya tidak bersih , saya lebih suka mengatur nilai batas waktu melalui konfigurasi Spring

<bean id="RestOperations" class="org.springframework.web.client.RestTemplate">
    <constructor-arg>

      <bean class="org.springframework.http.client.CommonsClientHttpRequestFactory">
        <property name="readTimeout" value="${restURL.connectionTimeout}" />
      </bean>
    </constructor-arg>
</bean>

Tampaknya apa pun yang saya atur readTimeout menjadi saya mendapatkan yang berikut:

Kabel jaringan terputus: Menunggu sekitar 20 detik dan melaporkan pengecualian berikut:

org.springframework.web.client.ResourceAccessExcep tion: Kesalahan I / O: Tidak ada rute ke host: hubungkan; pengecualian bersarang adalah java.net.NoRouteToHostException: Tidak ada rute ke host: sambungkan

Url salah jadi 404 dikembalikan oleh layanan istirahat: Menunggu sekitar 10 detik dan melaporkan pengecualian berikut:

org.springframework.web.client.HttpClientErrorException: 404 Tidak Ditemukan

Persyaratan saya memerlukan waktu tunggu yang lebih singkat, jadi saya harus dapat mengubahnya. Ada ide tentang apa yang saya lakukan salah?

Terimakasih banyak.

sardo
sumber

Jawaban:

164

Untuk Spring Boot> = 1.4

@Configuration
public class AppConfig
{
    @Bean
    public RestTemplate restTemplate(RestTemplateBuilder restTemplateBuilder) 
    {
        return restTemplateBuilder
           .setConnectTimeout(...)
           .setReadTimeout(...)
           .build();
    }
}

Untuk Spring Boot <= 1.3

@Configuration
public class AppConfig
{
    @Bean
    @ConfigurationProperties(prefix = "custom.rest.connection")
    public HttpComponentsClientHttpRequestFactory customHttpRequestFactory() 
    {
        return new HttpComponentsClientHttpRequestFactory();
    }

    @Bean
    public RestTemplate customRestTemplate()
    {
        return new RestTemplate(customHttpRequestFactory());
    }
}

lalu di application.properties

custom.rest.connection.connection-request-timeout=...
custom.rest.connection.connect-timeout=...
custom.rest.connection.read-timeout=...

Ini bekerja karena HttpComponentsClientHttpRequestFactorymemiliki setter publik connectionRequestTimeout, connectTimeout, dan readTimeoutdan @ConfigurationPropertiesset mereka untuk Anda.


Untuk Spring 4.1 atau Spring 5 tanpa menggunakan Spring Boot@Configuration sebagai gantinyaXML

@Configuration
public class AppConfig
{
    @Bean
    public RestTemplate customRestTemplate()
    {
        HttpComponentsClientHttpRequestFactory httpRequestFactory = new HttpComponentsClientHttpRequestFactory();
        httpRequestFactory.setConnectionRequestTimeout(...);
        httpRequestFactory.setConnectTimeout(...);
        httpRequestFactory.setReadTimeout(...);

        return new RestTemplate(httpRequestFactory);
    }
}
dustin.schultz
sumber
Contoh yang bagus! Tolong, hapus newpernyataan ganjil dalam Spring Bootcontoh
StasKolodyuk
7
Perhatikan bahwa setelah konfigurasi ini, RestTemplate akan menggunakan klien http apache (untuk mengatur waktu tunggu). Utas maxPerRoute default kumpulan koneksi klien http Apache adalah 5, dan total utas maks adalah 10 (httpClient-4.5.2). Kami perlu mengatur ini sendiri dalam beberapa situasi (seperti kami perlu terhubung ke banyak host dan membutuhkan lebih banyak koneksi).
bluearrow
2
Harap diperhatikan bahwa connectionRequestTimeoutatribut tidak tersedia sebelum 4.1.4. RELEASE
Taoufik Mohdit
Saya mencoba konfigurasi For Spring Boot> = 1.4 pada Spring Boot> = 2.1.8 dan saya tidak berhasil. Saya mengikuti posting ini ( zetcode.com/springboot/resttemplate ) untuk membuat konfigurasi itu.
Ângelo Polotto
@ ÂngeloPolotto tautan yang Anda posting memberikan saran yang sama dengan solusi ini. Artikel tersebut mengatakan: "Alternatifnya, kita dapat menggunakan RestTemplateBuilder untuk melakukan pekerjaan itu."
dustin.schultz
76

Saya akhirnya berhasil.

Saya pikir fakta bahwa proyek kami memiliki dua versi berbeda dari jar commons-httpclient tidak membantu. Setelah saya menyelesaikannya, saya menemukan Anda dapat melakukan dua hal ...

Dalam kode Anda dapat meletakkan yang berikut ini:

HttpComponentsClientHttpRequestFactory rf =
    (HttpComponentsClientHttpRequestFactory) restTemplate.getRequestFactory();
rf.setReadTimeout(1 * 1000);
rf.setConnectTimeout(1 * 1000);

Pertama kali kode ini dipanggil, waktu tunggu untuk HttpComponentsClientHttpRequestFactorykelas yang digunakan oleh RestTemplate. Oleh karena itu, semua panggilan berikutnya yang dilakukan oleh RestTemplateakan menggunakan pengaturan waktu tunggu yang ditentukan di atas.

Atau opsi yang lebih baik adalah melakukan ini:

<bean id="RestOperations" class="org.springframework.web.client.RestTemplate">
    <constructor-arg>
        <bean class="org.springframework.http.client.HttpComponentsClientHttpRequestFactory">
            <property name="readTimeout" value="${application.urlReadTimeout}" />
            <property name="connectTimeout" value="${application.urlConnectionTimeout}" />
        </bean>
    </constructor-arg>
</bean>

Di mana saya menggunakan RestOperationsantarmuka dalam kode saya dan mendapatkan nilai batas waktu dari file properti.

sardo
sumber
Jadi ini menetapkan batas waktu untuk semua panggilan melalui template rest ini (yang merupakan singleton). Apakah Anda tahu apakah mungkin mengontrol waktu tunggu per permintaan? (misalnya: 10 detik untuk panggilan pos dan 5 detik untuk panggilan, dll.)
codesalsa
@ sardo. Di mana saya menggunakan antarmuka RestOperations dalam kode saya. kita perlu membuat antarmuka eksplisit untuk ini?
deadend
Anda mengatakan bahwa Anda menggunakan Spring 3.0 - yang saya juga terjebak dengannya - tetapi di 3.0 tidak ada HttpComponentsClientHttpRequestFactory! Apakah Anda memperbarui Spring?
Kutzi
5
Kode di atas tidak berfungsi di Spring terbaru. Ini memberi ClassCastExceptionjava.lang.ClassCastException: org.springframework.http.client.InterceptingClientHttpRequestFactory cannot be cast to org.springframework.http.client.HttpComponentsClientHttpRequestFactory
comiventor
40

Pertanyaan ini adalah tautan pertama untuk pencarian Spring Boot, oleh karena itu, akan sangat bagus untuk meletakkan di sini solusi yang direkomendasikan dalam dokumentasi resmi . Spring Boot memiliki kacang kenyamanannya sendiri RestTemplateBuilder :

@Bean
public RestTemplate restTemplate(
        RestTemplateBuilder restTemplateBuilder) {

    return restTemplateBuilder
            .setConnectTimeout(Duration.ofSeconds(500))
            .setReadTimeout(Duration.ofSeconds(500))
            .build();
}

Pembuatan instans RestTemplate secara manual adalah pendekatan yang berpotensi merepotkan karena kacang yang dikonfigurasi secara otomatis lainnya tidak dimasukkan dalam instans yang dibuat secara manual.

Holdev
sumber
2
Catatan untuk pendatang baru Spring seperti saya: hanya menempelkan ini di @Configuration tidak akan melakukan apa-apa. Metode ini mengharuskan Anda memiliki RestTemplate yang disuntikkan di suatu tempat yang menggunakannya sebagai argumen untuk konstruktor RestTemplateXhrTransport yang pada gilirannya akan Anda tambahkan ke Daftar Transportasi yang Anda berikan ke SocksJSClient Anda.
Key Lay
setConnectTimeoutdan beberapa implementasi setReadTimeouttidak digunakan lagi
skryvets
17

Ini 2 sen saya. Tidak ada yang baru, tetapi beberapa penjelasan, peningkatan, dan kode yang lebih baru.

Secara default, RestTemplatememiliki waktu tunggu tak terbatas. Ada dua jenis batas waktu: batas waktu koneksi dan batas waktu pembacaan. Misalnya, saya dapat terhubung ke server tetapi saya tidak dapat membaca data. Aplikasi hang dan Anda tidak tahu apa yang sedang terjadi.

Saya akan menggunakan anotasi, yang sekarang lebih disukai daripada XML.

@Configuration
public class AppConfig {

    @Bean
    public RestTemplate restTemplate() {

        var factory = new SimpleClientHttpRequestFactory();

        factory.setConnectTimeout(3000);
        factory.setReadTimeout(3000);

        return new RestTemplate(factory);
    }
}

Disini kita gunakan SimpleClientHttpRequestFactoryuntuk mengatur koneksi dan membaca waktu habis. Ini kemudian diteruskan ke konstruktor dari RestTemplate.

@Configuration
public class AppConfig {

    @Bean
    public RestTemplate restTemplate(RestTemplateBuilder builder) {

        return builder
                .setConnectTimeout(Duration.ofMillis(3000))
                .setReadTimeout(Duration.ofMillis(3000))
                .build();
    }
}

Dalam solusi kedua, kami menggunakan RestTemplateBuilder. Perhatikan juga parameter dari dua metode: mereka mengambil Duration. Metode kelebihan beban yang memakan waktu langsung dalam milidetik sekarang sudah tidak digunakan lagi.

Edit Diuji dengan Spring Boot 2.1.0 dan Java 11.

Jan Bodnar
sumber
Versi musim semi dan java apa yang Anda gunakan?
orirab
2
Spring Boot 2.1.0 dan Java 11. Untuk contoh yang berfungsi, Anda dapat melihat tutorial saya: zetcode.com/springboot/resttemplate
Jan Bodnar
Saya sarankan menambahkan ini ke jawaban
orirab
Lihat github.com/spring-projects/spring-boot/blob/master/… . Itu ditambahkan di Spring Boot 2.1.0.
Jan Bodnar
Terima kasih @JanBodnar, tutorial Anda adalah satu-satunya yang bekerja dengan baik di Spring Boot 5.x saya
Ângelo Polotto
15

Berikut ini cara yang sangat sederhana untuk menyetel waktu tunggu:

RestTemplate restTemplate = new RestTemplate(getClientHttpRequestFactory());

private ClientHttpRequestFactory getClientHttpRequestFactory() {
    int timeout = 5000;
    HttpComponentsClientHttpRequestFactory clientHttpRequestFactory =
      new HttpComponentsClientHttpRequestFactory();
    clientHttpRequestFactory.setConnectTimeout(timeout);
    return clientHttpRequestFactory;
}
benscabbia.dll
sumber
0

Saya memiliki skenario serupa, tetapi juga diminta untuk mengatur Proxy. Cara paling sederhana yang dapat saya lihat untuk melakukan ini adalah dengan memperluas SimpleClientHttpRequestFactorykemudahan pengaturan proxy (proxy berbeda untuk non-prod vs prod). Ini harus tetap berfungsi meskipun Anda tidak memerlukan proxy. Kemudian di kelas saya yang diperluas, saya mengganti openConnection(URL url, Proxy proxy)metode, menggunakan sama dengan sumber , tetapi hanya mengatur batas waktu sebelum kembali.

@Override
protected HttpURLConnection openConnection(URL url, Proxy proxy) throws IOException {
    URLConnection urlConnection = proxy != null ? url.openConnection(proxy) : url.openConnection();
    Assert.isInstanceOf(HttpURLConnection.class, urlConnection);
    urlConnection.setConnectTimeout(5000);
    urlConnection.setReadTimeout(5000);
    return (HttpURLConnection) urlConnection;
}
Ryan D
sumber
0

Untuk memperluas jawaban benscabbia :

private RestTemplate restCaller = new RestTemplate(getClientHttpRequestFactory());

private ClientHttpRequestFactory getClientHttpRequestFactory() {
    int connectionTimeout = 5000; // milliseconds
    int socketTimeout = 10000; // milliseconds
    RequestConfig config = RequestConfig.custom()
      .setConnectTimeout(connectionTimeout)
      .setConnectionRequestTimeout(connectionTimeout)
      .setSocketTimeout(socketTimeout)
      .build();
    CloseableHttpClient client = HttpClientBuilder
      .create()
      .setDefaultRequestConfig(config)
      .build();
    return new HttpComponentsClientHttpRequestFactory(client);
}
Tasos Zervos
sumber
0
  1. RestTemplate timeout dengan SimpleClientHttpRequestFactory Untuk mengganti properti timeout secara terprogram, kita bisa menyesuaikan kelas SimpleClientHttpRequestFactory seperti di bawah ini.

Ganti waktu tunggu dengan SimpleClientHttpRequestFactory

//Create resttemplate
RestTemplate restTemplate = new RestTemplate(getClientHttpRequestFactory());

//Override timeouts in request factory
private SimpleClientHttpRequestFactory getClientHttpRequestFactory() 
{
    SimpleClientHttpRequestFactory clientHttpRequestFactory
                      = new SimpleClientHttpRequestFactory();
    //Connect timeout
    clientHttpRequestFactory.setConnectTimeout(10_000);

    //Read timeout
    clientHttpRequestFactory.setReadTimeout(10_000);
    return clientHttpRequestFactory;
}
  1. RestTemplate timeout dengan HttpComponentsClientHttpRequestFactory SimpleClientHttpRequestFactory membantu dalam mengatur timeout tetapi sangat terbatas dalam fungsionalitas dan mungkin tidak cukup terbukti dalam aplikasi realtime. Dalam kode produksi, kita mungkin ingin menggunakan HttpComponentsClientHttpRequestFactory yang mendukung pustaka Klien HTTP bersama dengan resttemplate.

HTTPClient menyediakan fitur berguna lainnya seperti kumpulan koneksi, manajemen koneksi idle, dll.

Read More: Contoh konfigurasi Spring RestTemplate + HttpClient

Ganti waktu tunggu dengan HttpComponentsClientHttpRequestFactory

//Create resttemplate
RestTemplate restTemplate = new RestTemplate(getClientHttpRequestFactory());

//Override timeouts in request factory
private SimpleClientHttpRequestFactory getClientHttpRequestFactory() 
{
    HttpComponentsClientHttpRequestFactory clientHttpRequestFactory
                      = new HttpComponentsClientHttpRequestFactory();
    //Connect timeout
    clientHttpRequestFactory.setConnectTimeout(10_000);

    //Read timeout
    clientHttpRequestFactory.setReadTimeout(10_000);
    return clientHttpRequestFactory;
}

referensi: Contoh konfigurasi timeout Spring RestTemplate

Zgpeace
sumber