Comparison and Practical Guide to Java etcd Clients
This article compares popular Java etcd client libraries, evaluates their features, performance, and suitability, and provides a hands‑on tutorial using jetcd with Maven dependencies, code examples for watching and reading keys, and discusses runtime considerations such as thread handling.
Previously I shared a Go implementation of etcd; now I discuss Java clients, noting that Go has the best support while Java options vary in quality, often resembling Web3j in asynchronous design and documentation.
Java Client Comparison
Feature
jetcd
etcd4j
spring-cloud-kubernetes
vertx-etcd-client
Maintainer
etcd-io (CoreOS)
jurmous
Spring Cloud
Eclipse Vert.x
etcd Compatibility
v3 API
mainly v2 API
v3 API
v3 API
Async Support
Yes
Yes
Yes
Yes
Dependency
gRPC
Netty
Spring Cloud
Vert.x
Features
Official support, full functionality
Lightweight, easy to use
Spring Cloud integration
Vert.x ecosystem integration
Use Cases
Large projects needing full features
Simple usage, legacy systems
Spring Cloud projects
Vert.x projects
Watch Support
Yes
Yes
Yes
Yes
Transaction Support
Yes
Limited
Via Spring abstraction
Yes
Performance
High
Medium
Depends on Spring abstraction
High
Community Activity
High
Low
High
Medium
Documentation Quality
Detailed
Average
Detailed
Detailed
Learning Curve
Medium
Low
High (if unfamiliar with Spring)
Medium
Detailed Comparison
jetcd Heavy dependency (gRPC) Potentially steep learning curve Official support, synchronized with etcd releases Full v3 API support Excellent performance for large‑scale production Pros: ... Cons: ...
etcd4j Primarily supports v2 API, limited v3 features Community updates are slower Not suitable for new projects requiring v3 features Lightweight and easy to integrate Simple, intuitive API Pros: ... Cons: ...
spring-cloud-kubernetes Depends on Spring ecosystem, unsuitable for non‑Spring projects May introduce unnecessary complexity for simple etcd usage Deep integration with Spring Cloud and Kubernetes Provides service discovery and configuration management Pros: ... Cons: ...
vertx-etcd-client Bound to Vert.x, not ideal for non‑Vert.x projects Smaller community Integrates with Vert.x ecosystem Non‑blocking API, suitable for high‑concurrency scenarios Pros: ... Cons: ...
Java Client Practice
Below I choose jetcd as the implementation library and add the following Maven dependencies:
<dependency>
<groupId>io.etcd</groupId>
<artifactId>jetcd-core</artifactId>
<version>0.7.0</version>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>31.1-jre</version>
</dependency>If you encounter a Exception in thread "main" java.lang.NoClassDefFoundError , verify server version, gRPC version, client version, and missing dependencies.
The following example demonstrates watching a key and performing basic write/read operations using jetcd :
package com.funtest.temp
import com.funtester.frame.SourceCode
import io.etcd.jetcd.ByteSequence
import io.etcd.jetcd.Client
import io.etcd.jetcd.Watch
import io.etcd.jetcd.kv.GetResponse
import io.etcd.jetcd.watch.WatchEvent
import java.nio.charset.Charset
import java.nio.charset.StandardCharsets
import java.util.concurrent.CompletableFuture
class TtcdTest extends SourceCode {
static Charset defaultCharset = StandardCharsets.UTF_8
// Create client, connect to etcd
static def client = Client.builder().endpoints("http://localhost:2379").build()
static def kVClient = client.getKVClient()
static def watchClient = client.getWatchClient()
/**
* Watch key changes in etcd and print them
*/
static watch() {
def key = toByteSequence("key")
Watch.Listener listener = Watch.listener(watchResponse -> {
for (WatchEvent event : watchResponse.getEvents()) {
println("watch change ------------------")
println("Event type: " + event.getEventType())
println("Key: " + event.getKeyValue().getKey().toString(StandardCharsets.UTF_8))
println("Value: " + event.getKeyValue().getValue().toString(StandardCharsets.UTF_8))
}
})
watchClient.watch(key, listener)
}
/**
* Write and read data
*/
static writeRead() {
kVClient.put(toByteSequence("key"), toByteSequence("FunTester")).get()
CompletableFuture
getFuture = kVClient.get(toByteSequence("key"))
GetResponse response = getFuture.get()
println("Value: " + response.getKvs().get(0).getValue().toString())
}
/**
* Convert String to ByteSequence
*/
static ByteSequence toByteSequence(String str, Charset = defaultCharset) {
return ByteSequence.from(str, defaultCharset);
}
}Execute the two methods:
public static void main(String[] args) {
watch();
writeRead();
}Console output shows the expected watch event and value retrieval, but the JVM does not exit even after calling client.close() , leaving several RUNNABLE threads and a fork‑join pool, similar to issues seen with Web3j and Netty.
Server Feature Test Performance Test Topics Java, Groovy, Go, Python Unit & White‑box & Tools Collection Testing Strategies, Bugs, Crawlers, UI Automation Testing Theory Soup Community Highlights & Video Collection
FunTester
10k followers, 1k articles | completely useless
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.