1. RestTemplate (синхронный клиент)
📌 Старый, но до сих пор используется. В Spring 6 считается устаревающим, но знать надо.
📄 Bean-конфигурация:
@Configuration
public class RestTemplateConfig {
@Bean
public RestTemplate restTemplate(RestTemplateBuilder builder) {
return builder
.setConnectTimeout(Duration.ofSeconds(3))
.setReadTimeout(Duration.ofSeconds(5))
.build();
}
}📄 Примеры использования:
@Service
@RequiredArgsConstructor
public class WeatherService {
private final RestTemplate restTemplate;
public WeatherDto getWeather(String city) {
String url = "https://api.weather.com/city/" + city;
return restTemplate.getForObject(url, WeatherDto.class);
}
public void createUser(UserDto user) {
restTemplate.postForEntity("http://localhost:8080/api/users", user, Void.class);
}
}2. WebClient (реактивный клиент)
📌 Современная альтернатива RestTemplate. Поддерживает асинхронность и реактивность.
📄 Bean-конфигурация:
@Configuration
public class WebClientConfig {
@Bean
public WebClient webClient(WebClient.Builder builder) {
return builder.baseUrl("https://api.weather.com")
.defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
.build();
}
}📄 Использование:
@Service
@RequiredArgsConstructor
public class WeatherService {
private final WebClient webClient;
public Mono<WeatherDto> getWeather(String city) {
return webClient.get()
.uri("/city/{city}", city)
.retrieve()
.bodyToMono(WeatherDto.class);
}
public Flux<UserDto> getUsers() {
return webClient.get()
.uri("/api/users")
.retrieve()
.bodyToFlux(UserDto.class);
}
}
📌 Mono<T> = один объект (аналог Optional),
Flux<T> = поток объектов (как List).3. OpenFeign (декларативный клиент)
📌 Если у тебя микросервисы → лучший выбор. Не нужно вручную писать RestTemplate или WebClient.
📄 Зависимость:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>📄 Включение:
@SpringBootApplication
@EnableFeignClients
public class DemoApplication {}📄 Интерфейс-клиент:
@FeignClient(name = "userClient", url = "http://localhost:8080/api/users")
public interface UserClient {
@GetMapping("/{id}")
UserDto getUser(@PathVariable Long id);
@PostMapping
UserDto createUser(@RequestBody UserDto dto);
}📄 Использование:
@Service
@RequiredArgsConstructor
public class UserService {
private final UserClient client;
public UserDto get(Long id) {
return client.getUser(id);
}
}4. Retry & Timeout (Resilience4j)
📌 Иногда внешнее API падает → надо повторять или ограничивать время ожидания.
📄 Зависимость:
<dependency>
<groupId>io.github.resilience4j</groupId>
<artifactId>resilience4j-spring-boot3</artifactId>
</dependency>📄 Конфигурация:
resilience4j.retry:
instances:
apiRetry:
maxAttempts: 3
waitDuration: 2s📄 Использование:
@Service
public class ExternalService {
@Retry(name = "apiRetry")
public String callApi() {
if (Math.random() > 0.7) {
return "Success!";
}
throw new RuntimeException("API failed");
}
}5. Circuit Breaker (предохранитель)
📌 Чтобы не завалить сервис постоянными запросами, если он уже падает.
📄 Конфигурация:
resilience4j.circuitbreaker:
instances:
apiBreaker:
failureRateThreshold: 50
waitDurationInOpenState: 10s
slidingWindowSize: 10📄 Использование:
@Service
public class ExternalService {
@CircuitBreaker(name = "apiBreaker", fallbackMethod = "fallback")
public String callApi() {
throw new RuntimeException("API error");
}
public String fallback(Throwable t) {
return "Fallback response";
}
}6. Async API calls (параллельные запросы)
CompletableFuture:
@Async
public CompletableFuture<UserDto> fetchUser(Long id) {
return CompletableFuture.supplyAsync(() -> client.getUser(id));
}WebClient:
Flux<UserDto> users = webClient.get()
.uri("/api/users")
.retrieve()
.bodyToFlux(UserDto.class);7. Best Practices
- ✅ Для синхронных API → RestTemplate (устаревающий, но встречается).
- ✅ Для асинхронных/реактивных сервисов → WebClient.
- ✅ Для микросервисов → Feign.
- ✅ Добавляй retry, timeout, circuit breaker через Resilience4j.
- ✅ Никогда не делай внешние вызовы без таймаутов.
- ✅ Логируй все запросы/ответы (Spring Boot Sleuth или кастомный LoggingInterceptor).