bigywater.tech
Spring · 117

DiscoveryClient 与 ServiceRegistry 抽象,自动注册的时机

服务到底是什么时候注册进注册中心的?预热没做完会不会就有流量进来?优雅停机时实例什么时候被摘掉?自己写一个 DiscoveryClient 会怎样合并?这篇在 Spring Boot 4.0.8、Spring Cloud 2025.1.3 上用一个自己实现的内存注册中心把时间线打出来。

1547 ms
实例已注册但应用还没就绪的时间窗口(算出来的),此时 ApplicationRunner 还在预热
2.4 秒
收到 SIGTERM 后实例仍然留在注册中心的时间(算出来的),此时就绪状态已是 REFUSING_TRAFFIC
serviceregistry
actuator 端点的 id,不是 service-registry

注册的时机

实测 · 本机执行输出
   1501 ms  AbstractAutoServiceRegistration.start() 被调用(getPhase() = 0,isAutoStartup = true)
   1502 ms  RegistrationLifecycle.postProcessBeforeStartRegister
   1502 ms  ServiceRegistry.register(x117-app, 端口 9601),线程 main
   1502 ms  RegistrationLifecycle.postProcessAfterStartRegister
   1503 ms  事件 ServletWebServerInitializedEvent
   1503 ms  SmartLifecycle probe.start()(phase 2147483547)
   1508 ms  事件 ContextRefreshedEvent
   1542 ms  事件 ApplicationStartedEvent
   1543 ms  事件 AvailabilityChangeEvent → CORRECT
   1544 ms  ApplicationRunner 开始(睡 1500 ms,模拟启动后的预热)
   3048 ms  ApplicationRunner 结束
   3049 ms  事件 ApplicationReadyEvent
   3049 ms  事件 AvailabilityChangeEvent → ACCEPTING_TRAFFIC
  (应用的真实端口是 9601,与 register 时的端口比较:一致)

Web 服务器启动后立即注册,早于 ApplicationRunner 和 ApplicationReadyEvent。

serviceregistry 端点

实测 · 本机执行输出
  GET /actuator/serviceregistry → HTTP 200 UP
  POST {"status":"OUT_OF_SERVICE"} → HTTP 200 
  再 GET → HTTP 200 OUT_OF_SERVICE
  服务端的 setStatus 日志:ServiceRegistry.setStatus(OUT_OF_SERVICE)

GET 读状态,POST 改状态,调用的是自己实现的 ServiceRegistry。

关闭自动注册

实测 · 本机执行输出
  register 被调用 0 次;AutoServiceRegistrationProperties 个数 = 0,AutoServiceRegistration 个数 = 0
  对照(默认开启):register 被调用 1 次;AutoServiceRegistrationProperties 个数 = 1,AutoServiceRegistration 个数 = 1

enabled=false 时没有 AutoServiceRegistrationProperties,不再注册。

关闭顺序

实测 · 本机执行输出
   2944 ms  事件 ApplicationReadyEvent
   2945 ms  事件 AvailabilityChangeEvent → ACCEPTING_TRAFFIC
   4250 ms  事件 AvailabilityChangeEvent → REFUSING_TRAFFIC
   4251 ms  事件 ContextClosedEvent
   4251 ms  SmartLifecycle probe.stop()
  GracefulShutdown: Commencing graceful shutdown. Waiting for active requests to complete
   6582 ms  /slow 处理完毕
  GracefulShutdown: Graceful shutdown complete
   6648 ms  AbstractAutoServiceRegistration.stop() 被调用
   6648 ms  RegistrationLifecycle.postProcessBeforeStopRegister
   6648 ms  ServiceRegistry.deregister(x117-app),线程 SpringApplicationShutdownHook
   6649 ms  RegistrationLifecycle.postProcessAfterStopRegister
   6649 ms  ServiceRegistry.close()
   6649 ms  ServiceRegistry.close()
  客户端:/slow 的响应 200 done,耗时 3.0 秒(SIGTERM 在请求开始 0.7 秒后发送)

先拒绝流量,等在途请求处理完,最后才 deregister。

DiscoveryClient

实测 · 本机执行输出
  fixed=(order -5,description FixedClient);compositeDiscoveryClient=CompositeDiscoveryClient(order 0,description Composite Discovery Client);simpleDiscoveryClient=SimpleDiscoveryClient(order 0,description Simple Discovery Client);
  组合后的 getServices() = [payments, orders, users] ,getInstances(orders) = [http://10.0.0.1:8080, http://10.0.0.2:8080],getInstances(payments) = [http://10.0.0.9:9000],description = Composite Discovery Client
  同样的配置再加 spring.cloud.discovery.enabled=false → fixed=(order -5,description FixedClient);compositeDiscoveryClient=CompositeDiscoveryClient(order 0,description Composite Discovery Client);simpleDiscoveryClient=SimpleDiscoveryClient(order 0,description Simple Discovery Client); | 组合后的 getServices() = [payments, orders, users] ,getInstances(orders) = [http://10.0.0.1:8080, http://10.0.0.2:8080],getInstances(payments) = [http://10.0.0.9:9000],description = Composite Discovery Client

Composite 合并所有 DiscoveryClient 的服务与实例。

分步演示

服务发现抽象
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 arm64 / OpenJDK 21.0.12(Homebrew) / Spring Boot 4.0.8(Spring Framework 7.0.9、Tomcat 11.0.24) / Spring Cloud 2025.1.3;用 javac 编译、java 直接运行,依赖由 Maven 从 Maven Central 解析;数字每次运行会有小幅抖动。没有真实的注册中心:ServiceRegistry、Registration、AbstractAutoServiceRegistration 的子类都是我写的内存实现,只记录调用;关闭顺序实验里用 server.shutdown=graceful,SIGTERM 在 /slow 请求开始 0.7 秒后发出;DiscoveryClient 部分用 SimpleDiscoveryClient 的配置加一个自定义 bean
    • 没有验证:真实注册中心(Nacos、Consul、Eureka)上这个时间线是不是一致,它们各自还有自己的健康检查与心跳;ServiceRegistry.close() 为什么被调用 2 次;AbstractAutoServiceRegistration 里注册发生在 WebServerInitializedEvent 监听器里这个说法(只看到 register 日志排在我的事件监听器日志之前);spring.cloud.discovery.enabled=false 真正影响的对象(这里没有看出变化);management 端口单独注册(register-management);RegistrationManagementLifecycle
    京ICP备2026067502号-1京公网安备11010502063487号