2015-03-27 4 views
3

Я работаю над проектом, в котором мне нужно сделать HTTP-URL-адрес на моем сервере, на котором запущена Restful Service, которая возвращает ответ в виде строки JSON. Я использую RestTemplate здесь вместе с HttpComponentsClientHttpRequestFactory для выполнения URL.Как эффективно использовать RestTemplate с помощью RequestFactory?

У меня установлен тайм-аут запроса HTTP (время простоя и время соединения) на моем RestTemplate с использованием HttpComponentsClientHttpRequestFactory.

Ниже мой интерфейс:

public interface Client { 

    // for synchronous 
    public String getSyncData(String key, long timeout); 

    // for asynchronous 
    public String getAsyncData(String key, long timeout); 
} 

Ниже моя реализация интерфейса клиента -

public class DataClient implements Client { 

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

    // for synchronous call 
    @Override 
    public String getSyncData(String key, long timeout) { 
     String response = null; 

     try { 
      Task task = new Task(key, restTemplate, timeout); 

      // direct call, implementing sync call as async + waiting is bad idea. 
      // It is meaningless and consumes one thread from the thread pool per a call.    
      response = task.call(); 
     } catch (Exception ex) { 
      PotoLogging.logErrors(ex, DataErrorEnum.CLIENT_ERROR, key); 
     } 

     return response; 
    } 

    // for asynchronous call 
    @Override 
    public Future<String> getAsyncData(String key, long timeout) { 
     Future<String> future = null; 

     try { 
      Task task = new Task(key, restTemplate, timeout); 
      future = executor.submit(task); 
     } catch (Exception ex) { 
      PotoLogging.logErrors(ex, DataErrorEnum.CLIENT_ERROR, key); 
     } 

     return future; 
    } 
} 

А ниже мой простой задачи класса

class Task implements Callable<String> { 

    private RestTemplate restTemplate; 
    private String key; 
    private long timeout; // in milliseconds 

    public Task(String key, RestTemplate restTemplate, long timeout) { 
     this.key = key; 
     this.restTemplate = restTemplate; 
     this.timeout = timeout; 
    } 

    public String call() throws Exception { 

     String url = "some_url_created_by_using_key"; 

     // does this looks right the way I am setting request factory? 
     // or is there any other effficient way to do this? 
     restTemplate.setRequestFactory(clientHttpRequestFactory()); 
     String response = restTemplate.exchange(url, HttpMethod.GET, null, String.class); 

     return response; 
    } 

    private static ClientHttpRequestFactory clientHttpRequestFactory() { 
     // is it ok to create a new instance of HttpComponentsClientHttpRequestFactory everytime? 
     HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory(); 
     factory.setReadTimeout(timeout); // setting timeout as read timeout 
     factory.setConnectTimeout(timeout); // setting timeout as connect timeout 
     return factory; 
    } 
} 

Теперь мой вопрос - Использует ли я RestTemplate вместе с setRequestFactory в ca ll метод класса Task каждый раз эффективен? Поскольку RestTemplate очень тяжело создавать, поэтому не уверен, правильно ли я понял.

И это нормально создавать новый экземпляр HttpComponentsClientHttpRequestFactory каждый раз? Будет ли это дорого?

Каков правильный и эффективный способ использования RestTemplate, если нам нужно настроить время прочтения и подключения к нему.

Эта библиотека будет использоваться, как это -

String response = DataClientFactory.getInstance().getSyncData(keyData, 100); 
+0

FYI Есть весна AsyncRestTemplate 4. –

+0

@AdamGent Я вижу, будет ли это полезно в моем сценарии? – john

+0

AsyncRestTemplate может потенциально полностью устранить необходимость в Задаче, поскольку она возвращает «Будущее». Вместо того, чтобы выбирать между непосредственным выполнением задачи или отправкой ее исполнителю, вы можете просто запустить запрос на обычном RestTemplate или Async. – xathien

ответ

2

Из того, что я могу сказать, что вы повторно использовать один и тот же объект RestTemplate неоднократно, но каждый Task выполняет эту строку: restTemplate.setRequestFactory(clientHttpRequestFactory());. Похоже, что он может иметь условия гонки, например. один Task может установить RequestFactory, чтобы затем случайно использовать Task.

В противном случае, похоже, вы правильно используете RestTemplate.

Как часто изменяются ваши таймауты? Если вы в основном используете один или два тайм-аута, вы можете создать один или два RestTemplate с помощью конструктора RequestFactory с предварительно установленным таймаутом. Если вы эффективны, создайте HashMap<Integer, RestTemplate>, который кэширует RestTemplate с определенным тайм-аутом каждый раз, когда запрашивается новый тайм-аут.

В противном случае, глядя на код для RestTemplate's constructor, и для HttpComponentsClientHttpRequestFactory's constructor, они не выглядят исключительно тяжелыми, поэтому их многократно называет, вероятно, не будет большим узким местом.

+0

Я вижу, что условия гонки объясняют то, что вы объяснили только после тщательного изучения кода. Как я могу избежать этого состояния гонки? – john

+0

Каждый клиент будет использовать эту библиотеку в своей базе кода, поэтому они будут иметь только один тайм-аут, поэтому они не будут изменять значения тайм-аута для каждого вызова.Как только он будет установлен, он будет использоваться для всех вызовов, которые они будут делать в этой библиотеке. – john

+0

Простой способ исправить состояние гонки - создать новый RestTemplate непосредственно перед созданием задачи. Тогда вам не нужно передавать тайм-аут в задачу вообще. Если одно использование библиотеки имеет только один тайм-аут, я бы предложил добавить DataClient.setTimeout (int timeout). Затем вы можете использовать один RestTemplate, один раз установить тайм-аут через эту функцию и продолжить работу. – xathien