web-dev-qa-db-fra.com

Comment utiliser efficacement RestTemplate dans un environnement multithread?

Je travaille sur un projet dans lequel je dois passer un appel URL HTTP à mon serveur, qui exécute Restful Service, qui renvoie la réponse sous forme de chaîne JSON.

Ci-dessous, mon code principal qui utilise les variables future et callables -

public class TimeoutThreadExample {

    private ExecutorService executor = Executors.newFixedThreadPool(10);

    public String getData() {
        Future<String> future = executor.submit(new Task());
        String response = null;

        try {
            response = future.get(100, TimeUnit.MILLISECONDS);
        } catch (TimeoutException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }

        return response;
    }
}

Ci-dessous, ma classe Task qui implémente l'interface Callable et utilise la RestTemplate...

class Task implements Callable<String> {

    private RestTemplate restTemplate = new RestTemplate();

    public String call() throws Exception {

        String url = "some_url";
        String response = restTemplate.getForObject(url, String.class);

        return response;
    }
}

Et maintenant, j'ai le code ci-dessous dans une autre classe DemoTest qui appelle la méthode getData dans TimeoutThreadExample classe 5000 times séquentiellement -

public class DemoTest { 
   public static void main(String[] args) {

        TimeoutThreadExample bc = new TimeoutThreadExample();

        for (int i = 0; i <= 5000; i++) {
        //  TimerTest timer = TimerTest.getInstance(); // line 1
            bc.getData();
        //  timer.getDuration(); // line 2
        }
    }
}       

Ma question est donc la suivante: RestTemplate devrait-il être statique ici dans mon Task class, comme si je le voyais correctement, je recrée le pool de connexions entier pour chaque demande dans RestTemplate, ce qui n’est pas le cas, je suppose ..

NOTE: / Si je rends RestTemplate statique, je constate une meilleure performance de bout en bout par rapport à une variable non statique RestTemplate après avoir commenté line1 et line2 dans la classe DemoTest qui mesure la performance.

En général, quelle est la bonne façon d'utiliser RestTemplate dans un environnement multithreading? Actuellement, j'appelle de manière séquentielle la méthode getData 5000 fois, mais certains clients l'appelleront de manière multithread. Ils ont donc besoin de savoir quel est le meilleur moyen d'avoir RestTemplate dans un environnement multithread.

Peut-être utiliser ConnectionFactory dans le constructeur RestTemplate? Des pensées?

METTRE À JOUR:-

public class TimeoutThreadExample {

    private ExecutorService executor = Executors.newFixedThreadPool(10);
    private RestTemplate restTemplate = new RestTemplate();

    public String getData() {
        Future<String> future = executor.submit(new Task(restTemplate));
        String response = null;

        try {
            response = future.get(100, TimeUnit.MILLISECONDS);
        } catch (TimeoutException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }

        return response;
    }
}

Et au-dessous de ma TaskClass

class Task implements Callable<String> {

    private RestTemplate restTemplate;

    public Task(RestTemplate restTemplate) {
        this.restTemplate = restTemplate;
    }

    public String call() throws Exception {

        String url = "some_url";
        String response = restTemplate.getForObject(url, String.class);

        return response;
    }
}
14
AKIWEB

Corrigez-moi si je n'ai pas compris votre question. Cela ressemble beaucoup au précédent ici .

Là, nous avons déterminé que RestTemplate est thread-safe. Il n'y a donc aucune raison de ne pas le partager là où cela a du sens, c'est-à-dire. partout où vous l'utilisez de la même manière. Votre exemple semble être l'endroit idéal pour le faire.

Comme vous l'avez dit, recréer une nouvelle instance de RestTemplate pour chaque instance de Task est une perte de temps.

Je créerais la RestTemplate dans TimeoutThreadExample et le passerais à la Task en tant qu'argument constructeur.

class Task implements Callable<String> {

    private RestTemplate restTemplate;

    public Task(RestTemplate restTemplate) {
        this.restTemplate = restTemplate;
    }

    public String call() throws Exception {

        String url = "some_url";
        String response = restTemplate.getForObject(url, String.class);

        return response;
    }
}

De cette façon, vous partagez l'instance RestTemplate entre tous vos objets Task.

Notez que RestTemplate utilise SimpleClientHttpRequestFactory pour créer ses connexions.

16

Mon modèle singleton REST multi-thread-safe est câblé comme ceci au printemps:

<bean class="org.Apache.commons.httpclient.params.HttpConnectionManagerParams" id="httpConnectionManagerParams">
    <property name="connectionTimeout" value="10000"/>
</bean>
<bean class="org.Apache.commons.httpclient.MultiThreadedHttpConnectionManager" id="httpConnectionManager">
    <property name="params" ref="httpConnectionManagerParams"/>
</bean>
<bean class="org.Apache.commons.httpclient.params.HttpClientParams" id="httpClientParams">
    <property name="authenticationPreemptive" value="true"/>
    <property name="soTimeout" value="10000"/>
</bean>
<bean class="org.Apache.commons.httpclient.HttpClient" id="httpClient">
    <constructor-arg ref="httpClientParams"/>
    <constructor-arg ref="httpConnectionManager"/>
</bean>
<bean class="org.springframework.http.client.CommonsClientHttpRequestFactory" id="httpClientFactory">
    <constructor-arg ref="httpClient"/>
</bean>
<bean class="org.springframework.security.oauth.consumer.client.OAuthRestTemplate" id="restTemplate">
    <constructor-arg ref="httpClientFactory"/>
    <constructor-arg ref="myResource"/>
    <property name="messageConverters">
        <list>
            <ref bean="marshallingHttpMessageConverter"/>
        </list>
    </property>
</bean>

Veuillez noter que j'utilise OAuthRestTemplate, et myResource fait référence aux ressources oauth que j'ai omises car elles ne sont pas pertinentes. Au lieu d'une OAuthRestTemplate, vous pourriez tout aussi facilement utiliser un org.springframework.web.client.RestTemplatehttp://docs.spring.io/spring/docs/3.2.4.RELEASE/javadoc-api/org/springframework/web/client/RestTemplate.html

4
Taylor

RestTemplateest thread-safe une fois construit , vous pouvez donc créer une instance et la faire partager par toutes vos tâches. Cela sera beaucoup plus efficace, car vous éliminerez le coût de construction de chaque tâche et réduirez la charge sur le ramasse-miettes. 

1
Raedwald