Servlet containers, clients

Servlet containers

Servlet Container
Blocking HTTP Requests
Non-Blocking HTTP Requests
WebSockets Support
Works Well with Kotlin Coroutines

Jetty

✅ Yes

✅ Yes (via async I/O)

✅ Yes

✅ Yes (with Coroutine-based APIs)

Tomcat

✅ Yes

✅ Yes (via async servlets)

✅ Yes

⚠️ Limited (needs adapters like ktor-server-tomcat)

Undertow

✅ Yes

✅ Yes (reactive streams)

✅ Yes

✅ Yes (used in ktor-server-undertow)

Netty (is not a servlet container—it's an event-driven network application framework that can be used to build non-blocking servers and clients)

⚠️ Not its primary model

✅ Yes (fully event-driven)

✅ Yes

✅ Yes (integrates well with Ktor and coroutines)

Clients

HTTP Client
Blocking Requests
Non-Blocking Requests
Coroutine Friendly
Additional Notes

RestTemplate

✅ Yes

❌ No

⚠️ Limited

Synchronous API, designed for Spring MVC.

WebClient (Reactor Netty (default in Spring Boot))

⚠️ Limited

✅ Yes

✅ Yes

Non-blocking, reactive web client from Spring WebFlux.

Ktor

✅ Yes

✅ Yes

✅ Yes

Designed for Kotlin; supports both blocking and non-blocking calls.

OkHttp

✅ Yes

✅ Yes

⚠️ Limited

Primarily synchronous but supports asynchronous requests; good for Kotlin coroutines.

Apache HttpClient

✅ Yes

⚠️ Limited

⚠️ Limited

Synchronous by default; can use Future for async.

Retrofit

✅ Yes

✅ Yes

✅ Yes

Works with OkHttp, designed for REST APIs; supports coroutines via extensions.

Vert.x Web Client

❌ No

✅ Yes

✅ Yes

Fully non-blocking and designed for asynchronous programming.

Spring’s WebClient is a non-blocking HTTP client, but it can use different underlying engines for handling HTTP requests.

What determines WebClient's underlying engine?

It depends on which Spring Boot starter you include:

  1. If using spring-boot-starter-webflux (Reactive)

    • WebClient defaults to Netty (via Reactor Netty).

    • Netty handles HTTP connections asynchronously.

  2. If using spring-boot-starter-web (Blocking, Tomcat)

    • WebClient uses Apache HttpClient or Java’s HttpURLConnection.

    • It can still be non-blocking at the application level, but the underlying client might not be fully asynchronous.

      • If you’re making a few HTTP requests per second → You can use a blocking client inside coroutines with Dispatchers.IO

Last updated

Was this helpful?