概述
微服务拆分之后,订单服务调用用户服务不能再写死 http://localhost:8081,因为用户服务会扩容成多个实例,IP 和端口随时在变。这一篇就把解决这个问题的 Eureka 注册中心跑起来:一个独立的微服务,三步配置,启动后打开控制台能看到实例列表。
纲要
- 角色划分
- Eureka Server:注册中心,保存「服务名 → 实例地址列表」的映射
- Eureka Client:服务提供者与消费者,注册信息、拉取列表都走这一端
- 核心流程
- 服务注册:provider 启动时上报自己的服务名、IP、端口
- 服务保存:Server 保管地址列表,靠心跳(默认 30s)判断实例存活
- 服务发现:consumer 按服务名拉取实例列表
- 远程调用:负载均衡挑一个实例发请求
- 动手搭建(五步)
- 建
eureka-server子模块 - 引
spring-cloud-starter-netflix-eureka-server依赖 - 启动类加
@EnableEurekaServer application.yml配端口、服务名、defaultZone- 启动并访问
http://127.0.0.1:10086验证控制台
- 建
- 关键坑:
defaultZone少写/eureka、漏掉@EnableEurekaServer、spring.application.name不写导致控制台显示UNKNOWN、端口冲突 - 延伸:集群为什么要互相注册;Eureka 2.x 停维护与 Nacos 替代
Eureka 的两个角色
注册中心解决的问题只有一个:让调用方通过服务名找到可用实例的真实地址。围绕这件事,Eureka 把参与方分成两类。
| 角色 | 对应依赖 | 职责 | 典型代表 |
|---|---|---|---|
| Eureka Server | spring-cloud-starter-netflix-eureka-server | 接收注册、保存地址列表、心跳检测、对外提供查询 | eureka-server 模块 |
| Eureka Client | spring-cloud-starter-netflix-eureka-client | 上报自身信息(注册)、拉取他人信息(发现) | user-service、order-service |
这里有个容易被忽略的点:注册和发现被封装在同一个 client 依赖里。一个微服务既可能是提供者,也可能是消费者,所以 Eureka 没有拆成两套 API,引入 eureka-client 就同时具备两种能力。也就是说,user-service 用这个依赖,order-service 也用这个依赖,配置写法几乎一样。
整体链路如下。
一次完整调用在时间轴上是这样铺开的。
搭建前的工程结构
注册中心必须是一个独立的微服务,不能塞进 user-service 里。原因很直接:注册中心自己要是挂掉重启,不应该牵连任何一个业务服务;反过来业务服务重启,也不该影响注册中心的地址列表。所以它单独建模块,单独占端口。
沿用前面的 cloud-demo 父工程,最终结构如下。
cloud-demo
├── pom.xml # 父工程,统一管理 SpringCloud / SpringBoot 版本
├── eureka-server # 注册中心(本篇主角)
│ ├── pom.xml
│ └── src/main
│ ├── java/cn/itcast/eureka/EurekaApplication.java
│ └── resources/application.yml
├── user-service # 服务提供者,后续注册进来
│ ├── pom.xml
│ └── src/main
│ ├── java/cn/itcast/user/UserApplication.java
│ └── resources/application.yml
└── order-service # 服务消费者,后续来拉取列表
├── pom.xml
└── src/main
├── java/cn/itcast/order/OrderApplication.java
└── resources/application.yml
父工程先把 eureka-server 登记进 <modules>,否则建了模块也不会参与构建。
<modules>
<module>user-service</module>
<module>order-service</module>
<module>eureka-server</module>
</modules>
引依赖:为什么不用写版本号
在 eureka-server 的 pom.xml 里加上服务端 starter。
<?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">
<parent>
<artifactId>cloud-demo</artifactId>
<groupId>cn.itcast.demo</groupId>
<version>1.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>eureka-server</artifactId>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
<!-- eureka 服务端 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
</dependencies>
</project>
注意这里没有 version。不是漏写,是踩在有版本管理的前提下才成立:父工程 cloud-demo 里用 dependencyManagement 导入了 spring-cloud-dependencies 这个 BOM,所有 SpringCloud 组件的版本已经在 BOM 里定义好了。
<properties>
<java.version>1.8</java.version>
<spring-cloud.version>Hoxton.SR10</spring-cloud.version>
</properties>
<dependencyManagement>
<dependencies>
<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>
父工程 spring-boot-starter-parent 的版本是 2.3.9.RELEASE,对应 SpringCloud Hoxton.SR10,Eureka 的 1.9.x 就在里面。写版本号不是不可以,只是后面升级 BOM 时会漏改,反而容易出「某个模块版本对不上」的诡异问题。
artifactId 后缀是 -server,说明这是服务端依赖。换成 -client 就是客户端依赖,这是选依赖时最容易看错的地方,两个名字只差一个词。
starter 的含义是:依赖里已经带好了 Eureka Server 的自动装配,理论上可以零配置启动。但自动装配需要一个开关,开关就是下一步的注解。
启动类:@EnableEurekaServer 是那个开关
package cn.itcast.eureka;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
@EnableEurekaServer
@SpringBootApplication
public class EurekaApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaApplication.class, args);
}
}
注解拆开看:
| 注解 | 作用 | 漏写会怎样 |
|---|---|---|
@SpringBootApplication | 开启 SpringBoot 自动配置、组件扫描 | 应用根本起不来 |
@EnableEurekaServer | 开启注册中心功能,导入 Eureka Server 的自动配置类 | 服务能启动,但 /eureka/** 全部 404,控制台打不开 |
两个注解顺序无所谓,但 @EnableEurekaServer 一定不能少。它做的事情是把 EurekaServerAutoConfiguration 拉进容器,注册中心的一整套 REST 接口(注册、续约、下线、查询)都是这么装上去的。
写完之后 IDE 里应该有一个 Eureka 的启动项。启动类的包名是 cn.itcast.eureka,注意别被组件扫描的范围挡住——它自己就在根包下,扫描没问题。
application.yml:三块配置各管什么
src/main/resources/application.yml:
server:
port: 10086 # 服务端口
spring:
application:
name: eurekaserver # eureka 的服务名称
eureka:
client:
service-url: # eureka 的地址信息
defaultZone: http://127.0.0.1:10086/eureka
三段配置,各自解决一个问题。
端口用 10086 是课程惯例,换别的也行,但要和下面的 defaultZone 一致,改一个必须改另一个。
服务名是 eurekaserver。这里最容易犯的错是干脆不写,Eureka 控制台 那一栏就会显示成 UNKNOWN。因为服务端启动时也会把自己当成一个微服务注册进去,没有名字就只能叫 UNKNOWN。
defaultZone 是注册中心的地址。既然自己就是注册中心,为什么还要配自己的地址?因为Eureka Server 自己也是一个微服务,启动时会把自己也注册到自己身上。这一步在单机环境下看起来多余,但它是为集群准备的:两台/三台 Eureka 互相把对方写进 defaultZone,就能彼此交换地址列表,数据才通。多节点写法就是把地址用逗号隔开。
eureka:
client:
service-url:
defaultZone: http://eureka1:10086/eureka,http://eureka2:10087/eureka
本篇是单节点,写自己就够了。到这里「服务名 + 地址」其实就是在做服务注册,这两项是注册动作的必要参数。
defaultZone 为什么必须带 /eureka 后缀
这是整个搭建过程里最经典的坑。地址写成 http://127.0.0.1:10086,启动时不会立刻报错,而是在注册阶段抛异常,或者实例状态一直是 DOWN。
原因是 Eureka Server 的 REST 接口挂在 /eureka 这个上下文路径下,注册用的是 /eureka/apps/{appName},查询用的是 /eureka/apps。defaultZone 指的是注册接口的基准地址,不是首页地址。少了后缀就等于请求打到了 http://127.0.0.1:10086/apps/...,自然 404。
正确:http://127.0.0.1:10086/eureka
错误:http://127.0.0.1:10086
错误:http://127.0.0.1:10086/eureka/ ← 尾部多余斜杠,某些版本会拼出 //eureka/apps,也出问题
顺带记住:浏览器里访问控制台用的是 http://127.0.0.1:10086,不带 /eureka;配置文件里写的是 http://127.0.0.1:10086/eureka,带。两者的区别就在这,别混着抄。
register-with-eureka 与 fetch-registry
两个开关经常和 defaultZone 一起出现,但课程里默认没配,先看它们默认值是什么。
| 配置项 | 默认值 | 含义 | 单节点下建议 |
|---|---|---|---|
eureka.client.register-with-eureka | true | 是否把自己注册到注册中心 | 可设 false |
eureka.client.fetch-registry | true | 是否拉取服务列表并缓存到本地 | 可设 false |
默认都是 true,所以课程里不配,Eureka 也会注册自己——这正是控制台「Instances currently registered with Eureka」里有 eurekaserver 一行的原因。
单节点部署时把它们关掉是常见做法:注册中心不需要发现别人,也不需要被自己发现,关掉能少一次无意义的注册请求和一份本地缓存。代价是控制台那一栏会空着,看不出「服务是否正常上报」,调试阶段反而不如留着。
eureka:
client:
register-with-eureka: false # 单节点不需要注册自己
fetch-registry: false # 单节点不需要拉取服务列表
service-url:
defaultZone: http://127.0.0.1:10086/eureka
结论:集群下必须保持默认 true(节点之间靠注册和拉取同步数据),单节点下关不关都行。遇到「控制台列表为空」先回头确认这两个开关,别急着怀疑网络。
启动与验证
找到 EurekaApplication 的 main 方法直接运行。IDEA 的 Services 面板会多出一个 EurekaApplication 启动项,启动日志里搜 Started EurekaApplication,端口是 10086。
浏览器访问 http://127.0.0.1:10086(IDEA 里直接点日志中的端口也能跳过去),看到的就是 Eureka 自带的管理页面。
+--------------------------------------------------------------------------------+
| Eureka [Last updated] |
+--------------------------------------------------------------------------------+
| System Status |
| Environment .................... test |
| Current time ................... Wed Sep 30 21:03:41 CST 2026 |
| Uptime ......................... 0000 00:02:15 |
| Memory ......................... 301M (max 402M, total 402M) |
| Available processors ........... 8 (of 8) |
+--------------------------------------------------------------------------------+
| DS Replicas |
| eurekaserver |
| <hr/> |
| Instances currently registered with Eureka |
| Application AMIs Availability Zones Status |
| EUREKASERVER n/a (1) UP (1) - Wang:10086 |
+--------------------------------------------------------------------------------+
| General Info |
| total-avail-memory ............ 402mb |
| num-of-cpus ................... 8 |
+--------------------------------------------------------------------------------+
三段内容各看什么:
- System Status:环境、启动时间、JVM 内存。用来确认应用真的起来了,不是缓存页面。
- DS Replicas:对等的注册中心节点。单机只有一个
eurekaserver。 - Instances currently registered with Eureka:最关键的一段,注册进来的实例列表。Application 列是服务名,后面跟着状态和地址,将来
userservice、orderservice都会出现在这里。
最后一段里的 UP 表示实例健康,DOWN 表示不可用。地址列在 Windows 上显示的往往是计算机名(本例是机器名 Wang)而不是 IP,这是本机解析行为,不影响使用;换成 IP 部署或调 eureka.instance.prefer-ip-address 后就会显示真实 IP。
常见启动报错排查
| 现象 | 原因 | 改法 |
|---|---|---|
| 访问首页 404,日志无异常 | 启动类漏了 @EnableEurekaServer | 补上注解(import 是 org.springframework.cloud.netflix.eureka.server.EnableEurekaServer) |
启动后报 com.netflix.discovery.shared.transport.TransportException / Cannot execute request on any known server | defaultZone 少写 /eureka,注册请求打到了 404 地址 | 地址补成 http://127.0.0.1:10086/eureka |
控制台实例名显示 UNKNOWN | spring.application.name 没配或写错层级 | 补 spring.application.name: eurekaserver |
端口被占用 Port 10086 was already in use | 上一次进程没退干净,或端口被别的程序占 | lsof -i:10086(Windows 用 netstat -ano | findstr 10086)杀掉进程,或换端口并同步改 defaultZone |
实例状态长时间是 DOWN | 注册中心和实例地址不通,或 hostname 解析异常 | 检查 defaultZone、hosts 文件,必要时配 eureka.instance.prefer-ip-address: true |
| 依赖拉不下来 / 类找不到 | spring-cloud.version 与 SpringBoot 版本不匹配 | 参照官方版本对照表,2.3.x 对应 Hoxton.SR10 |
关于 Eureka 的现状
Eureka 2.x 已经停止维护,Netflix 也不再继续开源版本的演进。课程里用它是因为概念干净、控制台直观,适合把「注册中心」这件事讲透。生产环境新建项目,现在多数会选 Nacos——同时做注册中心和配置中心,还带控制台和权重、命名空间之类的管理能力。迁移时注意一点:Nacos 的地址写法不带 /eureka 这类上下文,spring.cloud.nacos.discovery.server-addr 直接写 127.0.0.1:8848,别把 Eureka 的习惯直接搬过去。
关键配置速览
| 配置项 | 示例值 | 说明 |
|---|---|---|
server.port | 10086 | 注册中心端口,必须与 defaultZone 一致 |
spring.application.name | eurekaserver | 微服务名,不写会在控制台显示 UNKNOWN |
eureka.client.service-url.defaultZone | http://127.0.0.1:10086/eureka | 注册中心地址,必须带 /eureka 后缀 |
eureka.client.register-with-eureka | true(默认) | 是否注册自身,单节点可设 false |
eureka.client.fetch-registry | true(默认) | 是否拉取服务列表,单节点可设 false |
eureka.instance.prefer-ip-address | true | 需要显示真实 IP 而非主机名时开启 |
API 速览
Eureka Server 对外就是一组 REST 接口,配置里的 defaultZone 拼的就是它们的前缀。
| 方法 | 路径 | 说明 |
|---|---|---|
POST | /eureka/apps/{appName} | 服务注册,客户端启动时调用 |
PUT | /eureka/apps/{appName}/{instanceId} | 心跳续约,默认每 30 秒一次 |
DELETE | /eureka/apps/{appName}/{instanceId} | 服务下线,客户端优雅关闭时调用 |
GET | /eureka/apps | 查询全部实例,服务发现的核心接口 |
GET | /eureka/apps/{appName} | 按服务名查询实例列表 |
GET | / | Eureka 管理控制台页面 |
官方文档
总结
搭建 Eureka Server 的动作本身只有三步:引 eureka-server 依赖、启动类加 @EnableEurekaServer、配置文件写端口/服务名/defaultZone。
真正需要记住的是几个判断点:
- 依赖后缀是
-server还是-client,选错不会报错但功能对不上 defaultZone后面那截/eureka少不得,这是 404 的头号来源spring.application.name决定控制台里显示名字还是UNKNOWNregister-with-eureka、fetch-registry默认是true,单节点关掉是优化不是必须,集群下必须保留- 控制台里的实例列表,就是整个注册中心的产物,也是后面服务注册与服务发现的验证入口
下一步就是把 user-service 用 eureka-client 注册进来,再让 order-service 按服务名拉取并完成负载均衡调用。
转载自 CSDN-专业IT技术社区
原文链接:https://blog.csdn.net/Tyro_java/article/details/167168336




