ZooKeeper 作為分散式協調服務,常與 Spring 整合實現服務發現、配置中心、分散式鎖等功能。整合核心在於 Spring 對 ZooKeeper 客戶端的封裝與生命週期管理。
<dependencies>
<!-- Apache Curator:ZooKeeper 官方推薦高階客戶端 -->
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-framework</artifactId>
<version>5.2.0</version>
</dependency>
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-recipes</artifactId>
<version>5.2.0</version>
</dependency>
<!-- Spring 整合支援 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.3.0</version>
</dependency>
</dependencies>
@Configuration
public class ZookeeperConfig {
@Value("${zookeeper.connectString:localhost:2181}")
private String connectString;
@Value("${zookeeper.sessionTimeoutMs:60000}")
private int sessionTimeoutMs;
@Value("${zookeeper.connectionTimeoutMs:15000}")
private int connectionTimeoutMs;
@Bean(initMethod = "start", destroyMethod = "close")
public CuratorFramework curatorFramework() {
return CuratorFrameworkFactory.newClient(
connectString,
sessionTimeoutMs,
connectionTimeoutMs,
new ExponentialBackoffRetry(1000, 3)
);
}
@Bean
public CuratorFrameworkClient curatorClient(CuratorFramework client) {
return new CuratorFrameworkClient(client);
}
}
@Component
public class ServiceRegistry {
@Autowired
private CuratorFramework client;
public void registerService(String serviceName, String address, int port) throws Exception {
String path = "/services/" + serviceName + "/" + address + ":" + port;
client.create().creatingParentsIfNeeded()
.withMode(CreateMode.EPHEMERAL)
.forPath(path, JSON.toJSONBytes(new ServiceMeta(address, port)));
}
public List<ServiceMeta> discoverServices(String serviceName) throws Exception {
List<String> children = client.getChildren().forPath("/services/" + serviceName);
return children.stream()
.map(child -> {
try {
byte[] data = client.getData().forPath("/services/" + serviceName + "/" + child);
return JSON.parseObject(data, ServiceMeta.class);
} catch (Exception e) {
throw new RuntimeException(e);
}
})
.collect(Collectors.toList());
}
}
@Component
public class DistributedLock {
@Autowired
private CuratorFramework client;
public InterProcessMutex getLock(String lockName) {
return new InterProcessMutex(client, "/locks/" + lockName);
}
// 使用範例
public void executeWithLock(String lockName, Runnable task) {
InterProcessMutex lock = getLock(lockName);
try {
if (lock.acquire(10, TimeUnit.SECONDS)) {
try {
task.run();
} finally {
lock.release();
}
}
} catch (Exception e) {
throw new RuntimeException("Lock acquire failed", e);
}
}
}
zookeeper:
connectString: "zk1:2181,zk2:2181,zk3:2181"
sessionTimeoutMs: 60000
connectionTimeoutMs: 15000
namespace: "myapp"
/namespace/type/identifier完整實戰範例可參考:ZooKeeper 與 Spring 整合開發實戰