RestTemplate должен быть статически объявлен глобально?
Я использую Java Callable Future в своем коде. Ниже мой основной код, который использует будущее и вызываемые -
public class TimeoutThread {
public static void main(String[] args) throws Exception {
ExecutorService executor = Executors.newFixedThreadPool(5);
Future<String> future = executor.submit(new Task());
try {
System.out.println("Started..");
System.out.println(future.get(3, TimeUnit.SECONDS));
System.out.println("Finished!");
} catch (TimeoutException e) {
System.out.println("Terminated!");
}
executor.shutdownNow();
}
}
Ниже мой Task
класс, который реализует интерфейс Callable, и мне нужно сгенерировать URL в зависимости от имеющегося у нас имени хоста, а затем сделать вызов SERVERS, используя RestTemplate
, Если в первом имени хоста есть какое-либо исключение, я сгенерирую URL для другого имени хоста и попытаюсь позвонить.
class Task implements Callable<String> {
private static RestTemplate restTemplate = new RestTemplate();
@Override
public String call() throws Exception {
//.. some code
for(String hostname : hostnames) {
if(hostname == null) {
continue;
}
try {
String url = generateURL(hostname);
response = restTemplate.getForObject(url, String.class);
// make a response and then break
break;
} catch (Exception ex) {
ex.printStackTrace(); // use logger
}
}
}
}
Так что мой вопрос я должен объявить RestTemplate
как статическая глобальная переменная? Или оно не должно быть статичным в этом сценарии?
4 ответа
В любом случае это не имеет значения, static
или экземпляр.
RestTemplate
методы для выполнения HTTP-запросов поточнобезопасны, так что если у вас есть RestTemplate
экземпляр за Task
экземпляр или общий экземпляр для всех Task
экземпляры не имеют значения (за исключением сбора мусора).
Лично я бы создал RestTemplate
вне Task
класс и передать его в качестве аргумента Task
конструктор. (Используйте Инверсию Контроля, когда это возможно.)
С точки зрения параллелизма это не имеет значения. RestTemplate
является потокобезопасным, поэтому один или несколько экземпляров не имеют отношения к правильному функционированию программы.
Но вы можете рассмотреть AsyncRestTemplate
вместо этого, как показано здесь.
Также, как упоминают другие, вы должны рассмотреть подход IoC, чтобы отделить создание вашего клиента REST от его использования. Эта статья Мартина Фаулера является плодотворной дискуссией на эту тему.
В моем конкретном случае я нашел несколько причин, по которым можно хотеть иметь более одного экземпляра RestTemplate
,
RestTemplate - это способ вызова удаленной конечной точки, но интеграция HTTP выглядит обманчиво простой, и когда вы начинаете находить специальные сценарии, которые не применимы ко всем вызовам API, вы понимаете, что вам нужен способ определить некоторые параметры в каждом конкретном случае. основа.
Примерами таких сценариев являются следующие:
- В нашей компании работают разные команды, и по ошибке мы не согласились с форматом времени, который хотели использовать в наших моделях. Теперь разные API из разных команд используют разные форматы времени, что вынудило нас определить разные настройки отображения JSON для этих случаев. Это также может произойти, если вам придется использовать сторонние сервисы.
- Не все API, которые мы называем, имеют одинаковые соглашения об уровне обслуживания или ведут себя одинаково в течение всего года. В разгар сезона некоторые API могут поддерживать больше трафика и т. Д. Это означает, что параметры времени ожидания соединения могут отличаться для разных API, а иногда даже в зависимости от требований. Таким образом, такие параметры, как время ожидания соединения, время чтения и время записи, могут быть настроены по-разному в зависимости от вызываемой вами службы.
- Возможно, настройка автоматического выключателя, как и в Hytrix, может потребоваться настроить для каждой службы, и поэтому наличие экземпляра RestTemplate для каждой службы дает больше возможностей для настройки параметров в каждом конкретном случае.
Как уже говорилось, RestTemplate является потокобезопасным.
Но, для модульного теста, использование статической переменной доставит вам некоторые проблемы с его вызовами. Итак, рассмотрим внедрение RestTemplate с помощью конструктора класса:
@Service
class LoginService {
private final RestTemplate restTemplate;
public LoginService(final RestTemplate restTemplate) {
this.restTemplate = restTemplate;
}
}