1. RestTemplate (Synchroner Client)
📌 Alt, aber noch verwendet. In Spring 6 als veraltet (deprecated) angesehen, aber es ist wichtig, ihn zu kennen.
📄 Bean-Konfiguration:
@Configuration
public class RestTemplateConfig {
@Bean
public RestTemplate restTemplate(RestTemplateBuilder builder) {
return builder
.setConnectTimeout(Duration.ofSeconds(3))
.setReadTimeout(Duration.ofSeconds(5))
.build();
}
}📄 Verwendungsbeispiele:
@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 (Reactive Client)
📌 Moderne Alternative zu RestTemplate. Unterstützt Asynchronität und Reaktivität.
📄 Bean-Konfiguration:
@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();
}
}📄 Verwendung:
@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> = a single object (analogous to Optional),
Flux<T> = a stream of objects (like List).3. OpenFeign (Declarative Client)
📌 Wenn du Microservices hast → die beste Wahl. Es ist nicht nötig, RestTemplate oder WebClient manuell zu schreiben.
📄 Abhängigkeit:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>📄 Integration:
@SpringBootApplication
@EnableFeignClients
public class DemoApplication {}📄 Schnittstellen-Client:
@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);
}📄 Verwendung:
@Service
@RequiredArgsConstructor
public class UserService {
private final UserClient client;
public UserDto get(Long id) {
return client.getUser(id);
}
}4. Retry & Timeout (Resilience4j)
📌 Manchmal schlägt eine externe API fehl → du musst den Versuch wiederholen oder die Wartezeit begrenzen.
📄 Abhängigkeit:
<dependency>
<groupId>io.github.resilience4j</groupId>
<artifactId>resilience4j-spring-boot3</artifactId>
</dependency>📄 Konfiguration:
resilience4j.retry:
instances:
apiRetry:
maxAttempts: 3
waitDuration: 2s📄 Verwendung:
@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 (Fuse)
📌 Um zu verhindern, dass der Dienst mit ständigen Anfragen überlastet wird, wenn er bereits fehlschlägt.
📄 Konfiguration:
resilience4j.circuitbreaker:
instances:
apiBreaker:
failureRateThreshold: 50
waitDurationInOpenState: 10s
slidingWindowSize: 10📄 Verwendung:
@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 (Parallel requests)
Completable Future:
@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. Bewährte Vorgehensweisen
- ✅ Für synchrone APIs → RestTemplate (veraltet, aber noch anzutreffen).
- ✅ Für asynchrone/reaktive Dienste → WebClient.
- ✅ Für Microservices → Feign.
- ✅ Retry, Timeout, Circuit Breaker mit Resilience4j hinzufügen.
- ✅ Externe Aufrufe niemals ohne Timeouts durchführen.
- ✅ Alle Anfragen/Antworten protokollieren (Spring Boot Sleuth oder eigener LoggingInterceptor).