本文目录导读:

我来详细介绍如何开发Java服务发现案例,包含服务注册、发现、健康检查等核心功能。
项目结构
service-discovery-demo/
├── service-registry-center # 注册中心
├── service-provider # 服务提供者
├── service-consumer # 服务消费者
└── common # 公共模块
基础依赖配置
1 Maven父POM
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>service-discovery-demo</artifactId>
<version>1.0.0</version>
<packaging>pom</packaging>
<properties>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
<spring.boot.version>2.7.14</spring.boot.version>
<spring.cloud.version>2021.0.8</spring.cloud.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring.boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring.cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
</project>
自定义注册中心实现
1 注册中心服务端
// ServiceRegistryCenterApplication.java
package com.example.registry;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.*;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
@SpringBootApplication
@RestController
public class ServiceRegistryCenterApplication {
public static void main(String[] args) {
SpringApplication.run(ServiceRegistryCenterApplication.class, args);
}
}
// RegistryServerController.java
@RestController
@RequestMapping("/registry")
public class RegistryServerController {
// 服务注册表:serviceName -> List<ServiceInstance>
private final Map<String, Map<String, ServiceInstance>> registry = new ConcurrentHashMap<>();
// 服务注册
@PostMapping("/register")
public Result register(@RequestBody ServiceInstance instance) {
Map<String, ServiceInstance> instances = registry
.computeIfAbsent(instance.getServiceName(), k -> new ConcurrentHashMap<>());
String instanceId = instance.getHost() + ":" + instance.getPort();
instance.setInstanceId(instanceId);
instance.setRegisterTime(System.currentTimeMillis());
instance.setLastHeartbeat(System.currentTimeMillis());
instances.put(instanceId, instance);
return Result.success("注册成功", instance);
}
// 服务发现
@GetMapping("/discover/{serviceName}")
public Result discover(@PathVariable String serviceName) {
Map<String, ServiceInstance> instances = registry.get(serviceName);
if (instances == null || instances.isEmpty()) {
return Result.error("服务不存在");
}
// 过滤掉过期的实例(30秒无心跳)
long now = System.currentTimeMillis();
List<ServiceInstance> activeInstances = instances.values().stream()
.filter(instance -> now - instance.getLastHeartbeat() < 30000)
.collect(Collectors.toList());
if (activeInstances.isEmpty()) {
return Result.error("没有可用的服务实例");
}
// 简单的负载均衡:轮询
ServiceInstance selected = activeInstances.get(
(int)(System.currentTimeMillis() % activeInstances.size())
);
return Result.success("发现成功", selected);
}
// 心跳检测
@PutMapping("/heartbeat/{instanceId}")
public Result heartbeat(@PathVariable String instanceId) {
for (Map<String, ServiceInstance> instances : registry.values()) {
ServiceInstance instance = instances.get(instanceId);
if (instance != null) {
instance.setLastHeartbeat(System.currentTimeMillis());
return Result.success("心跳更新成功");
}
}
return Result.error("实例不存在");
}
// 服务下线
@DeleteMapping("/unregister/{instanceId}")
public Result unregister(@PathVariable String instanceId) {
for (Map<String, ServiceInstance> instances : registry.values()) {
if (instances.remove(instanceId) != null) {
return Result.success("下线成功");
}
}
return Result.error("实例不存在");
}
// 获取所有服务
@GetMapping("/services")
public Result getAllServices() {
Map<String, List<ServiceInstance>> result = new HashMap<>();
registry.forEach((serviceName, instances) -> {
List<ServiceInstance> activeList = instances.values().stream()
.filter(i -> System.currentTimeMillis() - i.getLastHeartbeat() < 30000)
.collect(Collectors.toList());
if (!activeList.isEmpty()) {
result.put(serviceName, activeList);
}
});
return Result.success("查询成功", result);
}
}
2 服务实例和结果对象
// ServiceInstance.java
package com.example.registry.model;
public class ServiceInstance {
private String instanceId;
private String serviceName;
private String host;
private int port;
private String ip;
private Map<String, String> metadata;
private long registerTime;
private long lastHeartbeat;
// getters and setters...
}
// Result.java
package com.example.registry.model;
public class Result<T> {
private int code;
private String message;
private T data;
public static <T> Result<T> success(String message, T data) {
Result<T> result = new Result<>();
result.setCode(200);
result.setMessage(message);
result.setData(data);
return result;
}
public static <T> Result<T> error(String message) {
Result<T> result = new Result<>();
result.setCode(500);
result.setMessage(message);
return result;
}
// getters and setters...
}
服务提供者实现
1 服务提供者客户端
// ServiceProviderApplication.java
package com.example.provider;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableScheduling;
@SpringBootApplication
@EnableScheduling
public class ServiceProviderApplication {
public static void main(String[] args) {
SpringApplication.run(ServiceProviderApplication.class, args);
}
}
// RegistryClient.java
@Component
public class RegistryClient {
@Value("${registry.server.url:http://localhost:8080}")
private String registryUrl;
@Value("${server.port}")
private int serverPort;
@Value("${spring.application.name}")
private String serviceName;
private String instanceId;
private final RestTemplate restTemplate;
public RegistryClient() {
this.restTemplate = new RestTemplate();
}
@PostConstruct
public void register() {
ServiceInstance instance = new ServiceInstance();
instance.setServiceName(serviceName);
instance.setHost(getLocalIp());
instance.setPort(serverPort);
try {
Result result = restTemplate.postForObject(
registryUrl + "/registry/register",
instance,
Result.class
);
if (result.getCode() == 200) {
ServiceInstance registered = (ServiceInstance) result.getData();
this.instanceId = registered.getInstanceId();
log.info("服务注册成功,instanceId: {}", instanceId);
}
} catch (Exception e) {
log.error("服务注册失败", e);
}
}
@PreDestroy
public void unregister() {
if (instanceId != null) {
try {
restTemplate.delete(registryUrl + "/registry/unregister/" + instanceId);
log.info("服务下线成功");
} catch (Exception e) {
log.error("服务下线失败", e);
}
}
}
// 定时心跳
@Scheduled(fixedRate = 10000)
public void sendHeartbeat() {
if (instanceId != null) {
try {
restTemplate.put(registryUrl + "/registry/heartbeat/" + instanceId, null);
} catch (Exception e) {
log.warn("心跳发送失败", e);
}
}
}
private String getLocalIp() {
try {
return InetAddress.getLocalHost().getHostAddress();
} catch (Exception e) {
return "127.0.0.1";
}
}
}
// UserServiceController.java
@RestController
@RequestMapping("/api/user")
public class UserServiceController {
@GetMapping("/info")
public Result getUserInfo(@RequestParam String userId) {
Map<String, Object> userInfo = new HashMap<>();
userInfo.put("userId", userId);
userInfo.put("name", "张三");
userInfo.put("email", "zhangsan@example.com");
userInfo.put("servicePort", serverPort); // 添加端口信息便于验证
return Result.success("查询成功", userInfo);
}
}
服务消费者实现
1 服务消费者客户端
// ServiceConsumerApplication.java
package com.example.consumer;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
@SpringBootApplication
public class ServiceConsumerApplication {
public static void main(String[] args) {
SpringApplication.run(ServiceConsumerApplication.class, args);
}
}
// ServiceDiscoveryClient.java
@Component
public class ServiceDiscoveryClient {
@Value("${registry.server.url:http://localhost:8080}")
private String registryUrl;
private final RestTemplate restTemplate;
public ServiceDiscoveryClient() {
this.restTemplate = new RestTemplate();
}
public ServiceInstance discoverService(String serviceName) {
try {
ResponseEntity<Result> response = restTemplate.getForEntity(
registryUrl + "/registry/discover/" + serviceName,
Result.class
);
Result result = response.getBody();
if (result != null && result.getCode() == 200) {
Map<String, Object> data = (Map<String, Object>) result.getData();
ServiceInstance instance = new ServiceInstance();
instance.setHost((String) data.get("host"));
instance.setPort((Integer) data.get("port"));
return instance;
}
} catch (Exception e) {
log.error("服务发现失败", e);
}
return null;
}
public String getServiceUrl(String serviceName, String path) {
ServiceInstance instance = discoverService(serviceName);
if (instance != null) {
return String.format("http://%s:%d%s",
instance.getHost(), instance.getPort(), path);
}
return null;
}
}
// UserConsumerController.java
@RestController
@RequestMapping("/api/consumer")
public class UserConsumerController {
@Autowired
private ServiceDiscoveryClient discoveryClient;
@GetMapping("/user/{userId}")
public Result getUserInfo(@PathVariable String userId) {
// 服务发现并调用
ServiceInstance instance = discoveryClient.discoverService("user-service");
if (instance == null) {
return Result.error("服务不可用");
}
String url = String.format("http://%s:%d/api/user/info?userId=%s",
instance.getHost(), instance.getPort(), userId);
try {
RestTemplate restTemplate = new RestTemplate();
Result result = restTemplate.getForObject(url, Result.class);
return result;
} catch (Exception e) {
return Result.error("服务调用失败: " + e.getMessage());
}
}
// 显示所有可用服务
@GetMapping("/services")
public Result getAllServices() {
String registryInfo = discoveryClient.getServiceUrl(
"registry-center", "/registry/services");
// 直接调用注册中心的API
RestTemplate restTemplate = new RestTemplate();
try {
return restTemplate.getForObject(
"http://localhost:8080/registry/services", Result.class);
} catch (Exception e) {
return Result.error("获取服务列表失败");
}
}
}
使用Nacos实现(生产推荐)
1 Nacos服务提供者
<!-- Nacos依赖 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
# application.yml
spring:
application:
name: nacos-provider
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848
namespace: public
group: DEFAULT_GROUP
server:
port: 8081
@SpringBootApplication
@EnableDiscoveryClient
public class NacosProviderApplication {
public static void main(String[] args) {
SpringApplication.run(NacosProviderApplication.class, args);
}
}
@RestController
public class ProviderController {
@Value("${server.port}")
private int port;
@GetMapping("/hello")
public String hello(@RequestParam String name) {
return String.format("Hello %s, from port %d", name, port);
}
}
2 Nacos服务消费者
# application.yml
spring:
application:
name: nacos-consumer
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848
server:
port: 8082
@SpringBootApplication
@EnableDiscoveryClient
public class NacosConsumerApplication {
@LoadBalanced
@Bean
public RestTemplate restTemplate() {
return new RestTemplate();
}
public static void main(String[] args) {
SpringApplication.run(NacosConsumerApplication.class, args);
}
}
@RestController
public class ConsumerController {
@Autowired
private RestTemplate restTemplate;
@Autowired
private DiscoveryClient discoveryClient;
@GetMapping("/consumer")
public String consume() {
// 使用负载均衡调用服务
String result = restTemplate.getForObject(
"http://nacos-provider/hello?name=World",
String.class
);
return "Consumer received: " + result;
}
@GetMapping("/services")
public List<String> getServices() {
// 获取所有服务
return discoveryClient.getServices();
}
@GetMapping("/instances/{serviceName}")
public List<ServiceInstance> getInstances(
@PathVariable String serviceName) {
// 获取服务的所有实例
return discoveryClient.getInstances(serviceName);
}
}
配置文件
1 自定义注册中心配置
# application-registry.properties server.port=8080 spring.application.name=registry-center
2 服务提供者配置
# application-provider.properties server.port=8081 spring.application.name=user-service registry.server.url=http://localhost:8080
3 服务消费者配置
# application-consumer.properties server.port=8082 spring.application.name=consumer-service registry.server.url=http://localhost:8080
测试和运行
1 启动顺序
# 1. 启动注册中心 mvn spring-boot:run -pl service-registry-center # 2. 启动服务提供者(可以启动多个实例) mvn spring-boot:run -pl service-provider -Dserver.port=8081 mvn spring-boot:run -pl service-provider -Dserver.port=8083 # 3. 启动服务消费者 mvn spring-boot:run -pl service-consumer -Dserver.port=8082
2 测试API
# 1. 查看注册的服务 curl http://localhost:8080/registry/services # 2. 服务发现 curl http://localhost:8080/registry/discover/user-service # 3. 消费者调用 curl http://localhost:8082/api/consumer/user/123 # 4. 查看消费者发现的服务 curl http://localhost:8082/api/consumer/services
高级特性
1 健康检查增强
@Component
public class HealthCheckEndpoint extends AbstractHealthIndicator {
@Override
protected void doHealthCheck(Health.Builder builder) throws Exception {
// 检查数据库连接
// 检查外部依赖
// 检查资源使用情况
if (isHealthy()) {
builder.up().withDetail("status", "Service is healthy");
} else {
builder.down().withDetail("error", "Service is unhealthy");
}
}
private boolean isHealthy() {
// 实现健康检查逻辑
return true;
}
}
2 负载均衡策略
@Component
public class CustomLoadBalancer implements LoadBalancer {
private final AtomicInteger position = new AtomicInteger(0);
@Override
public ServiceInstance choose(List<ServiceInstance> instances) {
if (instances.isEmpty()) {
return null;
}
// 加权随机
int totalWeight = instances.stream()
.mapToInt(this::getWeight)
.sum();
int random = new Random().nextInt(totalWeight);
int currentWeight = 0;
for (ServiceInstance instance : instances) {
currentWeight += getWeight(instance);
if (random < currentWeight) {
return instance;
}
}
// 默认轮询
int pos = Math.abs(position.incrementAndGet());
return instances.get(pos % instances.size());
}
private int getWeight(ServiceInstance instance) {
// 根据实例的配置或性能指标获取权重
return instance.getMetadata().getOrDefault("weight", "1");
}
}
最佳实践
-
服务命名规范:使用统一的命名格式,如
{业务域}-{服务名} -
健康检查:实现详细的自定义健康检查逻辑
-
熔断降级:结合Hystrix或Sentinel实现熔断
-
配置中心:使用Apollo或Nacos Config管理配置
-
监控告警:集成Prometheus和Grafana监控
-
安全防护:注册中心添加认证和授权机制
-
多环境支持:通过Namespace区分开发、测试、生产
这个案例涵盖了服务发现的核心功能,可以根据实际需求进行扩展和优化。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播