Zookeeper 用户服务注册与发现的 Java 代码实现

下面我将提供一个完整的 Zookeeper 实现服务注册与发现的 Java 代码示例,使用 Apache Curator 框架(Zookeeper 的高级客户端库)。

1. 添加 Maven 依赖

首先,在你的 pom.xml 中添加以下依赖:

<dependencies>
    <!-- Curator Framework -->
    <dependency>
        <groupId>org.apache.curator</groupId>
        <artifactId>curator-framework</artifactId>
        <version>5.2.0</version>
    </dependency>
    
    <!-- Curator Recipes -->
    <dependency>
        <groupId>org.apache.curator</groupId>
        <artifactId>curator-recipes</artifactId>
        <version>5.2.0</version>
    </dependency>
    
    <!-- Zookeeper -->
    <dependency>
        <groupId>org.apache.zookeeper</groupId>
        <artifactId>zookeeper</artifactId>
        <version>3.7.0</version>
    </dependency>
</dependencies>

2. 服务注册实现

import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.retry.ExponentialBackoffRetry;
import org.apache.curator.x.discovery.ServiceDiscovery;
import org.apache.curator.x.discovery.ServiceDiscoveryBuilder;
import org.apache.curator.x.discovery.ServiceInstance;
import org.apache.curator.x.discovery.UriSpec;
import org.apache.curator.x.discovery.details.JsonInstanceSerializer;

import java.util.Collection;

public class ServiceRegistry {

    private final ServiceDiscovery<InstanceDetails> serviceDiscovery;
    private final CuratorFramework client;

    public ServiceRegistry(String zookeeperAddress) throws Exception {
        // 创建 Curator 客户端
        client = CuratorFrameworkFactory.newClient(
                zookeeperAddress,
                new ExponentialBackoffRetry(1000, 3)
        );
        client.start();

        // 创建 ServiceDiscovery 实例
        JsonInstanceSerializer<InstanceDetails> serializer = 
            new JsonInstanceSerializer<>(InstanceDetails.class);
        
        serviceDiscovery = ServiceDiscoveryBuilder.builder(InstanceDetails.class)
                .client(client)
                .basePath("/services")
                .serializer(serializer)
                .build();
        
        serviceDiscovery.start();
    }

    public void registerService(String serviceName, String instanceId, String address, int port) throws Exception {
        // 创建服务实例
        ServiceInstance<InstanceDetails> instance = ServiceInstance.<InstanceDetails>builder()
                .name(serviceName)
                .id(instanceId)
                .address(address)
                .port(port)
                .uriSpec(new UriSpec("{scheme}://{address}:{port}"))
                .payload(new InstanceDetails("V1.0"))
                .build();

        // 注册服务
        serviceDiscovery.registerService(instance);
        System.out.println("Service registered: " + instance);
    }

    public Collection<ServiceInstance<InstanceDetails>> queryForInstances(String serviceName) throws Exception {
        return serviceDiscovery.queryForInstances(serviceName);
    }

    public void close() throws Exception {
        serviceDiscovery.close();
        client.close();
    }

    // 服务实例详情类
    public static class InstanceDetails {
        private String version;

        public InstanceDetails() {
        }

        public InstanceDetails(String version) {
            this.version = version;
        }

        public String getVersion() {
            return version;
        }

        public void setVersion(String version) {
            this.version = version;
        }
    }
}

3. 服务发现实现

import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.retry.ExponentialBackoffRetry;
import org.apache.curator.x.discovery.ServiceDiscovery;
import org.apache.curator.x.discovery.ServiceDiscoveryBuilder;
import org.apache.curator.x.discovery.ServiceInstance;
import org.apache.curator.x.discovery.details.JsonInstanceSerializer;

import java.util.Collection;

public class ServiceDiscoveryClient {

    private final ServiceDiscovery<ServiceRegistry.InstanceDetails> serviceDiscovery;
    private final CuratorFramework client;

    public ServiceDiscoveryClient(String zookeeperAddress) throws Exception {
        // 创建 Curator 客户端
        client = CuratorFrameworkFactory.newClient(
                zookeeperAddress,
                new ExponentialBackoffRetry(1000, 3)
        );
        client.start();

        // 创建 ServiceDiscovery 实例
        JsonInstanceSerializer<ServiceRegistry.InstanceDetails> serializer = 
            new JsonInstanceSerializer<>(ServiceRegistry.InstanceDetails.class);
        
        serviceDiscovery = ServiceDiscoveryBuilder.builder(ServiceRegistry.InstanceDetails.class)
                .client(client)
                .basePath("/services")
                .serializer(serializer)
                .build();
        
        serviceDiscovery.start();
    }

    public Collection<ServiceInstance<ServiceRegistry.InstanceDetails>> discoverServices(String serviceName) throws Exception {
        return serviceDiscovery.queryForInstances(serviceName);
    }

    public void close() throws Exception {
        serviceDiscovery.close();
        client.close();
    }
}

4. 使用示例

服务提供者 (注册服务)

public class ServiceProvider {
    public static void main(String[] args) throws Exception {
        String zookeeperAddress = "localhost:2181";
        String serviceName = "user-service";
        String instanceId = "user-service-1";
        String address = "192.168.1.100";
        int port = 8080;

        ServiceRegistry registry = new ServiceRegistry(zookeeperAddress);
        registry.registerService(serviceName, instanceId, address, port);

        // 保持服务运行
        Thread.sleep(Long.MAX_VALUE);
        
        registry.close();
    }
}

服务消费者 (发现服务)

public class ServiceConsumer {
    public static void main(String[] args) throws Exception {
        String zookeeperAddress = "localhost:2181";
        String serviceName = "user-service";

        ServiceDiscoveryClient discoveryClient = new ServiceDiscoveryClient(zookeeperAddress);
        
        while (true) {
            Collection<ServiceInstance<ServiceRegistry.InstanceDetails>> instances = 
                discoveryClient.discoverServices(serviceName);
            
            System.out.println("Discovered " + instances.size() + " instances:");
            for (ServiceInstance<ServiceRegistry.InstanceDetails> instance : instances) {
                System.out.println(" - " + instance.getAddress() + ":" + instance.getPort() + 
                                 " (Version: " + instance.getPayload().getVersion() + ")");
            }
            
            Thread.sleep(5000);
        }
        
        // discoveryClient.close(); // 实际应用中应该关闭
    }
}

5. 高级功能扩展

服务健康检查

import org.apache.curator.framework.recipes.healthcheck.HealthCheck;
import org.apache.curator.framework.recipes.healthcheck.HealthCheckListener;

public class HealthCheckExample {
    public static void addHealthCheck(CuratorFramework client, String servicePath) {
        HealthCheck healthCheck = new HealthCheck(client, servicePath);
        healthCheck.addListener(new HealthCheckListener() {
            @Override
            public void isHealthy(boolean healthy) {
                if (!healthy) {
                    System.out.println("Service is unhealthy: " + servicePath);
                    // 可以在这里触发服务重启或其他恢复操作
                }
            }
        });
        healthCheck.start();
    }
}

负载均衡

import org.apache.curator.x.discovery.ServiceProvider;
import org.apache.curator.x.discovery.strategies.RoundRobinStrategy;

public class LoadBalancer {
    private ServiceProvider<ServiceRegistry.InstanceDetails> serviceProvider;

    public LoadBalancer(ServiceDiscovery<ServiceRegistry.InstanceDetails> serviceDiscovery, 
                      String serviceName) throws Exception {
        serviceProvider = serviceDiscovery.serviceProviderBuilder()
                .serviceName(serviceName)
                .providerStrategy(new RoundRobinStrategy<>())
                .build();
        
        serviceProvider.start();
    }

    public ServiceInstance<ServiceRegistry.InstanceDetails> getInstance() throws Exception {
        return serviceProvider.getInstance();
    }

    public void close() throws Exception {
        serviceProvider.close();
    }
}

注意事项

  1. 确保 Zookeeper 服务已经启动并运行
  2. 在生产环境中,应该添加适当的异常处理和重试逻辑
  3. 考虑使用连接状态监听器来处理连接丢失和重新连接的情况
  4. 服务注册后应该定期检查健康状态
  5. 服务下线时应该正确注销服务实例

以上代码提供了一个完整的 Zookeeper 服务注册与发现实现,你可以根据实际需求进行调整和扩展。

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐