Spring WebClient vs RestTemplate
Web uygulamalarında diğer dış sitemlerle haberleşmek için HTTP çağrıları yapmak yaygın bir gerekliliktir. Diğer servislere çağrı yapmak için RestTemplate kullanıyoruz ancak bu en iyi seçenek mi?
RestTemplate, client tarafında senkronize HTTP isteklerini yürütmek için Spring kütüphanesi içindeki default sınıftır. Rest servislerin yaygınlaşmasından bu yana çoğu geliştirici, Rest servislerini çağırmak için spring-boot-starter-web paketindeki Spring’in geleneksel RestTemplate’iyle çalışmaya alıştı. Spring ayrıca spring-boot-starter-webflux paketinde WebClient adlı bir sınıfa sahiptir. Bu yazımız, RestTemplate’den WebClient’e geçiş yapmanız gerekip gerekmediğine karar vermenize yardımcı olacaktır.
RestTemplate/WebClient Avantajları ve Dezavantajları
RestTemplate
- RestTemplate thread-safe bir yapıdadır.
- RestTemplate servlet yapısı üzerine inşa edilmiştir. Bu yüzden thread-per-request yaklaşımını izler. Sonuç olarak uygulama, thread-pool’u tüketecek veya tüm kullanılabilir belleği kaplayacak birçok thread oluşturacaktır. Bu sebeple performans problemleri ortaya çıkacaktır.
- Spring 5 ile birlikte bakım moduna geçmiştir. Muhtemelen ilerleyen sürümlerde desteklenmeyecektir.
WebClient
- WebClient thread-safe çünkü immutable’dır.
- Senkron ve asenkron iletişimi destekler
- Reaktif yapı üzerine kurulmuştur.
- Spring 5 ile birlikte hayatımıza girmiştir. Bu sebeple ilerleyen sürümlerde desteklenecektir.
Bu iki yaklaşım arasındaki belirgin farkları görebilmek için, birçok eşzamanlı client isteğiyle performans testleri yapmamız gerekir. Belirli sayıda client isteğinden sonra RestTemplate’in thread-pool yoracağı yada tüm memory tüketerek önemli bir performans düşüşüne sebep olduğunu görürüz. Öte yandan reaktif yöntem, istek sayısına bakılmaksızın sürekli performanslı bir şekilde çalışmaya devam edecektir.
RestTemplate/WebClient Implementasyonları
RestTemplate
RestTemplate uygulanması oldukça basit ve sade bir yapıya sahiptir. Servis adresini, hangi HTTP yöntemi ile operasyonun gerçekleştirileceğini ve dönüş türünün ne olacağını veriyoruz.
ResponseEntity<Foo> response = restTemplate.exchange(uri, HttpMethod.GET, null, new ParameterizedTypeReference<Foo>(){}); List<Foo> result = response.getBody();
WebClient
WebClient ise biraz karmaşık gelebilir. Öncelikle hedef adresle bir WebClient örneği oluştururuz,
this.webClient = WebClient.builder().baseUrl("http://localhost:8080").build();
ardından gereksinimlerimize göre gerekli parametreleri yada headerları ekleyerek onu modifiye ederiz.
public Flux<Foo> getFoos() {
return webClient.get().uri("/foo")
.retrieve()
.bodyToFlux(Foo.class);
}public Mono<Foo> getFooById(int id) {
return webClient.get().uri("/foo/{id}",id)
.retrieve()
.bodyToMono(Foo.class);
}public Mono<Foo> createRecipe(Mono<Foo> foo) {
return webClient.post().uri("/foo")
.body(foo,Foo.class)
.retrieve()
.bodyToMono(Foo.class);
}public Mono<Void> deleteFoo(int id) {
return webClient.delete().uri("/foo/{id}", id)
.retrieve()
.bodyToMono(Void.class);
}public Mono<Foo> getFooByTitle(String title) {
Map<String, String> requestParameters = new HashMap<>();
requestParameters.put("title", title);
return webClient.get().uri("/foo", requestParameters)
.retrieve()
.bodyToMono(Foo.class);
}
Diyelim harici servisimiz reaktif değil. Ancak yine de WebClient kullanmak istiyoruz. O zaman Flux ve Mono bizim için pek işe yaramaz, bu yüzden onları açmak zorunda kalacağız. Bu sebeple block() kullanabiliriz.
Bunun reaktif bir ortamda kullanılmaması gerektiğini unutmayın.
public List<Foo> getFoos() {
Mono<List<Foo>> fooListStream = webClient.get()
.uri("/foo")
.retrieve()
.bodyToMono(
new ParameterizedTypeReference<List<Foo>>(){});
List<Foo> fooList = fooListStream.block();
return fooList;
}
Böylelikle yazımızın sonuna geldik, umarım faydalı bir yazı olmuştur. Bir sonraki buluşmaya kadar esenlikle kalın. 👏🏻
Kaynaklar
- https://docs.spring.io/spring-boot/docs/2.1.18.RELEASE/reference/html/boot-features-webclient.html
- https://www.baeldung.com/spring-webclient-resttemplate
- https://medium.com/techno101/webclient-vs-resttemplate-spring-boot-with-implementation-5b1aedf18f84
- https://ordina-jworks.github.io/rest/2020/10/12/RestTemplate-vs-WebClient.html