本文目录导读:

在Java中实现服务发现,主要有两种主流方式:使用现成的注册中心(如Nacos、Consul、Eureka) 或 自行开发基于DNS或HTTP的简单方案。
下面我会从最常用的生产级方案(Spring Cloud + Nacos) 和手动实现的简易方案两个角度来给出案例。
生产级方案(Spring Cloud Alibaba + Nacos)
这是目前国内最主流的搭配,功能强大,自带控制台。
环境准备
- 启动Nacos Server:
下载Nacos(https://github.com/alibaba/nacos/releases),解压后运行
bin/startup.cmd -m standalone(单机模式)。 访问http://localhost:8848/nacos,默认账号密码nacos/nacos。
Maven依赖(服务提供方 + 消费方都需要)
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.6.13</version>
</parent>
<dependencies>
<!-- Spring Cloud Alibaba Nacos Discovery
注意版本对应关系 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
<version>2021.0.5.0</version>
</dependency>
<!-- Web依赖(用于提供/调用接口) -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
服务提供方(Provider)
application.yml
server:
port: 8081
spring:
application:
name: user-service # 服务名,消费方通过这个名字调用
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848 # Nacos地址
启动类
@SpringBootApplication
@EnableDiscoveryClient // 启用服务发现(新版本可省略,加上了更明确)
public class UserServiceApplication {
public static void main(String[] args) {
SpringApplication.run(UserServiceApplication.class, args);
}
}
Controller (提供API)
@RestController
@RequestMapping(“/users”)
public class UserController {
@GetMapping(“/{id}”)
public String getUser(@PathVariable String id) {
return “User info for id: ” + id + “ from port: 8081”;
}
}
服务消费方(Consumer)
application.yml
server:
port: 8090
spring:
application:
name: order-service
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848
使用 RestTemplate + @LoadBalanced (负载均衡调用)
@SpringBootApplication
@EnableDiscoveryClient
public class OrderServiceApplication {
public static void main(String[] args) {
SpringApplication.run(OrderServiceApplication.class, args);
}
// 注入一个具有负载均衡能力的RestTemplate
@Bean
@LoadBalanced
public RestTemplate restTemplate() {
return new RestTemplate();
}
}
Controller (调用UserService)
@RestController
@RequestMapping(“/order”)
public class OrderController {
@Autowired
private RestTemplate restTemplate;
@GetMapping(“/user/{userId}”)
public String getOrderUser(@PathVariable String userId) {
// 注意:这里用的是服务名 “user-service”,不是具体的IP和端口
String url = “http://user-service/users/” + userId;
String userInfo = restTemplate.getForObject(url, String.class);
return “Order info, user: ” + userInfo;
}
}
验证效果
- 启动 Provider(8081),启动 Consumer(8090)。
- 访问
http://localhost:8090/order/user/123,应返回Order info, user: User info for id: 123 from port: 8081。 - 打开 Nacos 控制台,可以看到
user-service和order-service都已经注册成功。
手动实现简易服务发现(基于HTTP + 内存注册表)
如果不依赖Spring Cloud,想理解核心原理,可以自己实现一个轻量版。
核心思想:
- 服务注册:启动时,服务方将自己的 IP:Port + 服务名 发送给注册中心。
- 服务发现:消费方从注册中心拉取服务列表,然后根据负载均衡策略选择一个IP调用。
服务注册中心代码(Registry Center)
使用Spring Boot + ConcurrentHashMap
@RestController
@RequestMapping(“/registry”)
@SpringBootApplication
public class RegistryCenterApplication {
// 内存注册表: Key=服务名, Value=IP:Port列表
private static final ConcurrentHashMap<String, List<String>> SERVICE_MAP = new ConcurrentHashMap<>();
public static void main(String[] args) {
SpringApplication.run(RegistryCenterApplication.class, args);
}
// 注册接口
@PostMapping(“/register”)
public String register(@RequestParam String serviceName, @RequestParam String address) {
SERVICE_MAP.computeIfAbsent(serviceName, k -> new CopyOnWriteArrayList<>()).add(address);
System.out.println(“Registered: ” + serviceName + “ -> ” + address);
return “success”;
}
// 服务发现接口(获取所有实例)
@GetMapping(“/discover/{serviceName}”)
public List<String> discover(@PathVariable String serviceName) {
return SERVICE_MAP.getOrDefault(serviceName, Collections.emptyList());
}
// 心跳检测/剔除(简易版略,生产需加定时任务判断节点是否存活)
}
application.yml (端口 8761)
server: port: 8761
服务提供方(UserService)
@SpringBootApplication
public class UserServiceApplication {
public static void main(String[] args) {
SpringApplication.run(UserServiceApplication.class, args);
}
// 注册逻辑
@Bean
public CommandLineRunner registerToCenter(RestTemplate restTemplate) {
return args -> {
String serviceName = “user-service”;
String address = “localhost:8081”; // 本机地址
// 向注册中心注册
restTemplate.postForEntity(
“http://localhost:8761/registry/register?serviceName=” + serviceName + “&address=” + address,
null,
String.class
);
System.out.println(“Registered to registry center.”);
};
}
@RestController
public class UserApi {
@GetMapping(“/users/{id}”)
public String getUser(@PathVariable String id) {
return “User ” + id + “ from manual registry”;
}
}
}
服务消费方(OrderService)
@SpringBootApplication
public class OrderServiceApplication {
@Autowired
private RestTemplate restTemplate;
public static void main(String[] args) {
SpringApplication.run(OrderServiceApplication.class, args);
}
@RestController
public class OrderApi {
@GetMapping(“/invoke”)
public String invokeUserService() {
// 1. 从注册中心发现服务
List<String> instances = restTemplate.getForObject(
“http://localhost:8761/registry/discover/user-service”,
List.class
);
if (instances == null || instances.isEmpty()) {
return “No available service”;
}
// 2. 简单负载均衡:取第一个(生产应使用轮询/随机)
String target = instances.get(0);
// 3. 调用服务
String result = restTemplate.getForObject(“http://” + target + “/users/1”, String.class);
return “Result from discovered service: ” + result;
}
}
}
核心概念对比与总结
| 特性 | 方案一(Nacos/生产级) | 方案二(手动/教学级) |
|---|---|---|
| 注册中心稳定性 | 高,支持集群、持久化、CP+AP | 低,单机,内存存储 |
| 健康检查 | 自动心跳检测、剔除不健康节点 | 需自己实现 |
| 负载均衡 | 内置(Ribbon/LoadBalancer) | 需手动实现轮询/随机 |
| 配置管理 | Nacos自带配置中心,可动态刷新 | 无 |
| 使用场景 | 微服务生产环境 | 理解原理、小项目或学习 |
- 在实际企业Java项目中,强烈推荐使用 Spring Cloud Alibaba + Nacos 或 Spring Cloud + Consul,这些组件已经解决了高可用、健康检查、负载均衡、配置同步等复杂问题。
- 如果想快速理解服务发现的本质,可以自己用
HTTP+ConcurrentHashMap实现一遍流程,你会发现核心就是:一个集中存储服务地址的地方 + 一个用来获取地址的客户端。
版权声明: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直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播