上一篇我们介绍了Spring Cloud常用的服务发现组件Eureka,并且着手搭建了一个Eureka Server,本篇我们就将之前编写的服务提供者注册到Eureka Server上。
目录
一、客户端注册Eureka Server
启动Eureka Server,访问其首页,可以看到目前注册中心还没有任何注册信息:
我们以用户微服务为例,将其注册到Eureka Server上。我们打开Spring Cloud(Finchley.SR2版)的API文档:
https://cloud.spring.io/spring-cloud-static/Finchley.SR2/single/spring-cloud.html
找到“III. Spring Cloud Netflix”章节,然后在“11.1 How to Include Eureka Client”中可以看到(下面为机翻,语句不通请见谅^_^):
11.1如何包含Eureka客户端(How to Include Eureka )
要在项目中包含Eureka Client,请使用具有group ID:org.springframework.cloud和artifact ID:spring-cloud-starter-netflix-eureka-client。有关使用当前Spring Cloud Release Train设置构建系统的详细信息,请参阅Spring Cloud Project页面。11.2在Eureka注册
当客户向Eureka注册时,它会提供有关自身的元数据 - 例如主机,端口,运行状况指示器URL,主页和其他详细信息。Eureka从属于服务的每个实例接收心跳消息。如果心跳故障超过可配置的时间表,则通常会从注册表中删除该实例。以下示例显示了最小的Eureka客户端应用程序:@SpringBootApplication @RestController public class Application { @RequestMapping("/") public String home() { return "Hello world"; } public static void main(String[] args) { new SpringApplicationBuilder(Application.class).web(true).run(args); } }
请注意,前面的示例显示了一个普通的Spring Boot应用程序。通过spring-cloud-starter-netflix-eureka-client在类路径上,您的应用程序会自动向Eureka Server注册。找到Eureka服务器需要进行配置,如以下示例所示:
application.yml:eureka: client: serviceUrl: defaultZone: http://localhost:8761/eureka/
在前面的示例中,“defaultZone”是一个后备值,它为任何不表示首选项的客户端提供服务URL(换句话说,它是一个有用的默认值)。
默认的应用程序名称(即服务ID),虚拟主机,和非安全端口(从Environment获取)分别是${spring.application.name},${spring.application.name}和${server.port}。
在spring-cloud-starter-netflix-eureka-client类路径上使应用程序成为Eureka“实例”(即它注册自己)和“客户端”(它可以查询注册表以查找其他服务)。实例行为由eureka.instance.*配置键驱动,但如果您确保应用程序具有值spring.application.name(这是Eureka服务ID或VIP 的默认值),则默认值很好。
有关可配置选项的更多详细信息,请参阅EurekaInstanceConfigBean和EurekaClientConfigBean。
要禁用Eureka Discovery Client,您可以设置eureka.client.enabled为false。
可以看到,如果要注册到Eureka Server,首先要引入Eureka Client,即在POM文件中引入以下依赖:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
我们在microserver-provider-user工程的pom.xml中的<dependencies>标签中放置该依赖。
然后通过上面的API,我们也可以了解到,只要引入了spring-cloud-starter-netflix-eureka-client依赖,就会自动程序会自动向Eureka Server注册,我们只需要在application.yml配置Eureka服务器信息即可:
eureka:
client:
serviceUrl:
defaultZone: http://eureka1:8761/eureka
注意:这里的eureka1是在hosts中配置的127.0.0.1的域名映射。
加上之前的配置,的完整配置文件如下:
server:
port: 7900
spring:
jpa:
generate-ddl: false
show-sql: true
hibernate:
ddl-auto: none
datasource:
platform: h2
schema: classpath:schema.sql
data: classpath:data.sql
logging:
level:
root: info
org.hibernate: INFO
org.hibernate.type.descripter.sql.BasicBinder: TRACE
org.hibernate.type.descripter.sql.BasicExtractor: TRACE
com.microserver: DEBUG
eureka:
client:
serviceUrl:
defaultZone: http://eureka1:8761/eureka
如果学习过之前版本的Eureka的童鞋可能会有疑问,因为在之前的版本中,必须要自己在启动类加上@EnableEurekaClient才能够引入客户端,这里为什么不需要了呢?我查询了相关的资料,以及官方文档,都没有很好的解释,希望了解原因的童鞋可以帮忙解释一下。(2019年12月13日更新:Finchley.RELEASE版本的SpringCloud不需要@EnableEurekaClient注解就可以启用注册功能。在SpringBoot的自动配置类里启用了注册功能,只要引了eureka-client的依赖就会进行注册)
如果使用了@EnableEurekaClient注解,这里说明一下,@EnableEurekaClient注解只是针对Eureka来使用的,如果使用Zookeeper等服务发现组件,则需要使用@EnableDiscoveryCient注解。其实上@EnableEurekaClient注解是@EnableDiscoveryCient注解的一个别名注解。
我们下面重启microserver-provider-user工程以及注册中心microserver-discovery-eureka工程:
然后打开eureka的首页:
可以看到有一个客户端进行了注册,Status中的状态是UP(正常启用中)。但是我们可以看到有一些数据是不全的,例如Application(应用名)现在是UNKNOW,而Status中我们想显示的域名不是localhost,而是真实ip,所以引出以下问题:
(1)如何设置客户端的应用名?
指定应用名称,在yml文件中加入spring.application.name即可。
所以我们在刚才的microserver-provider-user工程的yml文件中,“spring:”下一个级别中添加如下配置:
spring:
application:
name: microserver-provider-user
设置该工程的应用名称为“microserver-provider-user”。
注意设置应用名时,不要进行大小写混写,很容易会混淆,最佳实践就是统一使用小写。
(2)如何设置客户端注册的域名为ip地址?
指定打开客户端ip地址,在yml文件中加入eureka.instance.prefer-ip-address即可。
所以我们在刚才的microserver-provider-user工程的yml文件中,“eureka:”下一个级别中添加如下配置:
eureka:
client:
serviceUrl:
defaultZone: http://eureka1:8761/eureka
instance:
prefer-ip-address: true
这样就可以向Eureka服务端暴露自己的具体ip地址。
注:此处也可以自定义服务地址的显示方式,使用“eureka.instance.instanceId”配置即可,如:
eureka:
instance:
instanceId:${spring.application.name}:${spring.application.instance_id:${server.port}}
之前版本为“eureka.instance.instance-id”。
我们修改了上述参数后,关闭microserver-provider-user工程。细心的朋友可以发现,在我们关闭 工程的时候,可以看到Eureka服务端的控制台显示了注册工程掉线的情况:
这就是Eureka心跳检测注册服务的健康机制。可以看到Eureka主页上我们的注册服务也是Down(下线)的状态:
重启microserver-provider-user工程,观察eureka服务端的日志,可以看到相关应用名对应的服务已经启动:
然后刷新Eureka的主页,可以看到相关参数已经更新上去了:
但是我们会发现,Eureka报出了以下错误;
EMERGENCY! EUREKA MAY BE INCORRECTLY CLAIMING INSTANCES ARE UP WHEN THEY'RE NOT. RENEWALS ARE LESSER THAN THRESHOLD AND HENCE THE INSTANCES ARE NOT BEING EXPIRED JUST TO BE SAFE.
并且之前的UNKONW节点也没有被剔除,这是为什么呢?
参考https://cloud.tencent.com/developer/article/1152507,原因如下:
这是因为Eureka进入了自我保护机制,默认情况下,如果EurekaServer在一定时间内没有接收到某个微服务实例的心跳时,EurekaServer将会注销该实例(默认90s)。但是当网络发生故障时,微服务与EurekaServer之间无法通信,这样就会很危险了,因为微服务本身是很健康的,此时就不应该注销这个微服务,而Eureka通过自我保护机制来预防这种情况,当网络健康后,该EurekaServer节点就会自动退出自我保护模式。
这时再次将客户端微服务启动,刷新服务注册中心会发现,自我保护状态已取消:
二、为Eureka Server进行认证
一些时候,我们并不想让所有人都可以看到Eureka Server的监控信息,我们想添加类似账号密码的登录机制,来进行查看的限制;同时我们也不想让无关的服务随意注册到Eureka Server上,需要客户端在提供相应的证明(如账号密码)之后才能够注册到 Eureka 中。
此时我们只需要给Eureka Server添加认证机制即可,该认证机制是基于HTTP Basic 的简单的用户名密码认证。添加了认证机制后,当访问Eureka Server时,会弹出认证窗口,输入正确的账号密码后,才可以进入Eureka Server的监控首页;同时所有的Eureka客户端也需要在配置文件中添加相应的认证信息才可以注册到Eureka中。
如何为Eureka Server添加认证呢?
首先在eureka server工程pom文件中引入eureka的安全认证依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
然后在eureka server工程的yml配置文件中添加security相关的配置
spring:
security:
user:
name: user
password: password123
即“spring.security.user.name”和“spring.security.user.password”
然后修改eureka server工程的yml配置的defaultZone的链接即可:
defaultZone: http://user:password123@eureka1:8761/eureka
可以看到,我们在之前的defaultZone前面添加了“user:password123@”的配置,格式为:
eureka.client.serviceUrl.defaultZone=http://${userName}:${password}@localhost:8761/eureka
这里要注意的是,由于Finchey版本默认开启csrf(Cross-site request forgery跨站请求伪造),而上面defaultZone那种组合方式,会被认为是跨站请求伪造,所以为了让其它客户端可以使用 http://${userName}:${password}@${host}:${port}/eureka/ 这种方式登录,需要关闭csrf,开启httpBasic。
所以这里我们需要编写一个配置类,来关闭csrf,开启httpBasic认证。所以我们在工程下的com.microserver.cloud.eureka包下新建一个WebSecurityConfig配置类:
package com.microserver.cloud.eureka;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
@EnableWebSecurity
@Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.NEVER);
http.csrf().disable(); //关闭csrf
//注意:为了可以使用 http://${user}:${password}@${host}:${port}/eureka/ 这种方式登录,所以必须是httpBasic,如果是form方式,不能使用url格式登录
http.authorizeRequests().anyRequest().authenticated().and().httpBasic(); //开启认证
}
}
添加了以上配置,就为eureka server设置了认证机制。
注意,以下方法已经过时:
# 此种方法已经过时
security:
basic:
enabled: true
user:
name: admin # 用户名
password: admin123 # 用户密码
我们重启eureka server工程,访问首页地址后可以看到:
输入账号密码进行登录,认证成功。
但是此时在首页,我们发现之前注册的user服务不见了:
这是因为在user服务中,defaultZone的配置没有添加账号和密码,导致认证失败,无法注册到注册中心:
eureka:
client:
serviceUrl:
defaultZone: http://eureka1:8761/eureka
我们将microserver-provider-user工程的上述配置修改为:
eureka:
client:
serviceUrl:
defaultZone: http://user:password123@eureka1:8761/eureka
然后重启microserver-provider-user工程,注册恢复正常:
三、监控和管理生产环境-actuator
有时候我们不仅要通过Eureka Server来查看各个服务的注册情况,同时可能也对各个服务的一些健康状态、运行情况等比较关心,此时Spring Boot提供的actuator依赖可以满足我们这种需求。
spring-boot-actuator模块提供了一个监控和管理生产环境的模块,可以使用http、jmx、ssh、telnet等管理和监控应用,审计(Auditing)、健康(health)、数据采集(metrics gathering)会自动加入到应用里面。
我们试验一下,在microserver-provider-user工程的pom文件中添加actuator依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
然后重启应用,观察控制台,发现开启了很多url请求节点:
我们访问http://localhost:7900/actuator/health,可以看到当前应用的健康状态:
其中UP表示应用是健康的,如果应用不健康将会显示DOWN。
然后访问http://localhost:7900/actuator/info,发现什么也没有:
这是因为,info展示了关于应用的基本信息,而这些基本信息从编译文件比如META-INF/build-info.properties或者Git文件比如git.properties或者任何环境的property中获取。我们这里没有配置这些,所以没有显示。但是它同时可以展示任何其他信息,只要这个环境yml/property中含有infokey。那么我们就在yml添加一些info:
info:
app:
name: "@project.name@"
description: "@project.description@"
version: "@project.version@"
encoding: "@project.build.sourceEncoding@"
java:
version: "@java.version@"
为了防止硬编码,这里参数使用了maven的编译环境的参数。
重启服务后,访问info,这些自定义基本信息就出来了:
补充:在eureka server中注册的服务,在status列表可以通过链接访问该服务的info端点:
然后访问http://localhost:7900/actuator,展示出了目前可以访问的所有监控端点(json串):
这里其实就是控制台打印的那三种。
在默认的情况下,actuator只暴露health和info,也说明了为什么控制台打印的暴露的endpoint只有/actuator/health和/actuator/info。而实际上,actuator给我们提供了超多有用的endpoint,所以我们需要了解如何暴露其它的endpoint。
我们先来看一下actuator给我们提供的一些很有用的endpoint:
在https://docs.spring.io/spring-boot/docs/current/reference/html/production-ready-endpoints.html上可以看到完整列表。
我们可以通过应用的yml/properties配置HTTP或JMX方式,来暴露需要的actuator endpoint:
●通过HTTP暴露Actuator endpoints:
management:
endpoints:
web:
exposure:
include:
- health,info
exclude:
-
或
# Use "*" to expose all endpoints, or a comma-separated list to expose selected ones
management.endpoints.web.exposure.include=health,info
management.endpoints.web.exposure.exclude=
●通过JMX暴露Actuator endpoints:
management:
endpoints:
jmx:
exposure:
include:
- health,info
exclude:
-
或
# Use "*" to expose all endpoints, or a comma-separated list to expose selected ones
management.endpoints.jmx.exposure.include=health,info
management.endpoints.jmx.exposure.exclude=
如果设置management.endpoints.web.exposure.include为*就可以开放所有端点,我们在microserver-provider-user工程的yml添加如下配置:
management:
endpoints:
web:
exposure:
include:
"*"
exclude:
-
补充1:使用properties文件配置模式为management.endpoints.web.exposure.include=*
补充2:* 在YAML中有特殊的含义,所以如果你想包含(或排除)所有的端点,在yml文件中一定要加引号。
重启应用后,访问http://localhost:7900/actuator,可以看到:
下面引用一篇博文的内容,解释一些重要的端点:
作者:alvin_wang
链接:https://www.jianshu.com/p/d5943e303a1f
来源:简书解析常用的actuator endpoint
/health endpoint
health endpoint通过合并几个健康指数检查应用的健康情况。
Spring Boot Actuator有几个预定义的健康指标比如DataSourceHealthIndicator, DiskSpaceHealthIndicator, MongoHealthIndicator, RedisHealthIndicator, CassandraHealthIndicator等。它使用这些健康指标作为健康检查的一部分。
举个例子,如果你的应用使用Redis,RedisHealthindicator将被当作检查的一部分。如果使用MongoDB,那么MongoHealthIndicator将被当作检查的一部分。
你也可以关闭特定的健康检查指标,比如在prpperties中使用如下命令:
management.health.mongo.enabled=false默认,所有的这些健康指标被当作健康检查的一部分。
显示详细的健康信息
health endpoint只展示了简单的UP和DOWN状态。为了获得健康检查中所有指标的详细信息,你可以通过在application.yaml中增加如下内容:management: endpoint: health: show-details: always
一旦你打开上述开关,你在/health中可以看到如下详细内容:
{"status":"UP","details":{"diskSpace":{"status":"UP","details":{"total":250790436864,"free":27172782080,"threshold":10485760}}}}
health endpoint现在包含了DiskSpaceHealthIndicator。
如果你的应用包含database(比如MySQL),health endpoint将显示如下内容:{ "status":"UP", "details":{ "db":{ "status":"UP", "details":{ "database":"MySQL", "hello":1 } }, "diskSpace":{ "status":"UP", "details":{ "total":250790436864, "free":100330897408, "threshold":10485760 } } } }
如果你的MySQL server没有启起来,状态将会变成DOWN:
{ "status":"DOWN", "details":{ "db":{ "status":"DOWN", "details":{ "error":"org.springframework.jdbc.CannotGetJdbcConnectionException: Failed to obtain JDBC Connection; nested exception is java.sql.SQLTransientConnectionException: HikariPool-1 - Connection is not available, request timed out after 30006ms." } }, "diskSpace":{ "status":"UP", "details":{ "total":250790436864, "free":100324585472, "threshold":10485760 } } } }
创建一个自定义的健康指标
你可以通过实现HealthIndicator接口来自定义一个健康指标,或者继承AbstractHealthIndicator类。package com.example.actuator.health; import org.springframework.boot.actuate.health.AbstractHealthIndicator; import org.springframework.boot.actuate.health.Health; import org.springframework.stereotype.Component; @Component public class CustomHealthIndicator extends AbstractHealthIndicator { @Override protected void doHealthCheck(Health.Builder builder) throws Exception { // Use the builder to build the health status details that should be reported. // If you throw an exception, the status will be DOWN with the exception message. builder.up() .withDetail("app", "Alive and Kicking") .withDetail("error", "Nothing! I'm good."); } }
一旦你增加上面的健康指标到你的应用中去后,health endpoint将展示如下细节:
{ "status":"UP", "details":{ "custom":{ "status":"UP", "details":{ "app":"Alive and Kicking", "error":"Nothing! I'm good." } }, "diskSpace":{ "status":"UP", "details":{ "total":250790436864, "free":97949245440, "threshold":10485760 } } } }
/metrics endpoint
metrics endpoint展示了你可以追踪的所有的度量。
{ "names": [ "jvm.memory.max", "http.server.requests", "process.files.max", ... "tomcat.threads.busy", "process.start.time", "tomcat.servlet.error" ] }
想要获得每个度量的详细信息,你需要传递度量的名称到URL中,像
http://localhost:8080/actuator/metrics/{MetricName}
举个例子,获得systems.cpu.usage的详细信息,使用以下URLhttp://localhost:8080/actuator/metrics/system.cpu.usage。它将显示如下内容:{ "name": "system.cpu.usage", "measurements": [ { "statistic": "VALUE", "value": 0 } ], "availableTags": [] }
/loggers endpoint
loggers endpoint,可以通过访问http://localhost:8080/actuator/loggers来进入。它展示了应用中可配置的loggers的列表和相关的日志等级。
你同样能够使用http://localhost:8080/actuator/loggers/{name}来展示特定logger的细节。
举个例子,为了获得root logger的细节,你可以使用http://localhost:8080/actuator/loggers/root:{ "configuredLevel":"INFO", "effectiveLevel":"INFO" }
在运行时改变日志等级
loggers endpoint也允许你在运行时改变应用的日志等级。
举个例子,为了改变root logger的等级为DEBUG ,发送一个POST请求到http://localhost:8080/actuator/loggers/root,加入如下参数{ "configuredLevel": "DEBUG" }
这个功能对于线上问题的排查非常有用。
同时,你可以通过传递null值给configuredLevel来重置日志等级。/info endpoint
info endpoint展示了应用的基本信息。它通过META-INF/build-info.properties来获得编译信息,通过git.properties来获得Git信息。它同时可以展示任何其他信息,只要这个环境property中含有infokey。
你可以增加properties到application.yaml中,比如:# INFO ENDPOINT CONFIGURATION info: app: name: @project.name@ description: @project.description@ version: @project.version@ encoding: @project.build.sourceEncoding@ java: version: @java.version@
注意,我使用了Spring Boot的Automatic property expansion 特征来扩展来自maven工程的properties。
一旦你增加上面的properties,info endpoint将展示如下信息:
{ "app": { "name": "actuator", "description": "Demo project for Spring Boot", "version": "0.0.1-SNAPSHOT", "encoding": "UTF-8", "java": { "version": "1.8.0_161" } } }
四、使用EurekaClient对象
我们通过Eureka Client的客户端机制(开启@EnableEurekaClient注解),可以将自己应用的信息注册到Eureka,那么同样的,我们可以通过EurekaClient来获取EurekaServer暴露的其它信息(例如其它应用名称对应的ip、端口信息)。下面就是一个实例,来通过EurekaClient获取其它应用名称(这里其实是它自己的应用名MICROSERVER-PROVIDER-USER)对应的ip、端口信息,在microserver-provider-user工程的UserController中添加一个“eureka-instance”服务:
package com.microserver.cloud.controller;
import java.util.Optional;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import com.microserver.cloud.dao.UserRepository;
import com.microserver.cloud.entity.User;
import com.netflix.appinfo.InstanceInfo;
import com.netflix.discovery.EurekaClient;
@RestController
public class UserController {
@Autowired
private UserRepository userDao;
@Autowired
EurekaClient eurekaClient;
@GetMapping("/findById/{id}")
public User findById(@PathVariable Long id){
Optional<User> userOptional = this.userDao.findById(id);
return userOptional.get();
}
@GetMapping("/eureka-instance")
public String serviceUrl(){
InstanceInfo instance = eurekaClient.getNextServerFromEureka("MICROSERVER-PROVIDER-USER", false);
return instance.getHomePageUrl();
}
}
重启该工程,访问eureka-instance服务:
可以看到我们从Eureka服务端获取了该应用对应的信息。
如果我们的注册中心使用的不是Eureka,我们也可以通过org.springframework.cloud.client.discovery.DiscoveryClient对象(Eureka也通用)来获取注册中心的相关信息,例如下面的例子:
@Autowired
DiscoveryClient discoveryClient;
@GetMapping("/instance-info")
public List<ServiceInstance> showInfo(){
List<ServiceInstance> instances = discoveryClient.getInstances("MICROSERVER-PROVIDER-USER");
return instances;
}
重启后,访问“instance-info”服务可以得到:
这里获取了MICROSERVER-PROVIDER-USER应用的所有服务注册信息,格式化一下:
[
{
"metadata": {
"jmx.port": "60863",
"management.port": "7900"
},
"host": "192.168.3.1",
"scheme": null,
"serviceId": "MICROSERVER-PROVIDER-USER",
"instanceInfo": {
"asgName": null,
"actionType": "ADDED",
"leaseInfo": {
"registrationTimestamp": 1561971144425,
"evictionTimestamp": 0,
"serviceUpTimestamp": 1561966510388,
"durationInSecs": 90,
"renewalIntervalInSecs": 30,
"lastRenewalTimestamp": 1561971144425
},
"homePageUrl": "http://192.168.3.1:7900/",
"metadata": {
"jmx.port": "60863",
"management.port": "7900"
},
"secureHealthCheckUrl": null,
"lastUpdatedTimestamp": 1561971144425,
"instanceId": "localhost:microserver-provider-user:7900",
"dataCenterInfo": {
"@class": "com.netflix.appinfo.InstanceInfo$DefaultDataCenterInfo",
"name": "MyOwn"
},
"lastDirtyTimestamp": 1561971143866,
"healthCheckUrl": "http://192.168.3.1:7900/actuator/health",
"status": "UP",
"sid": "na",
"statusPageUrl": "http://192.168.3.1:7900/actuator/info",
"app": "MICROSERVER-PROVIDER-USER",
"vipAddress": "microserver-provider-user",
"hostName": "192.168.3.1",
"isCoordinatingDiscoveryServer": false,
"ipAddr": "192.168.3.1",
"overriddenStatus": "UNKNOWN",
"appGroupName": null,
"countryId": 1,
"secureVipAddress": "microserver-provider-user"
},
"secure": false,
"uri": "http://192.168.3.1:7900",
"port": 7900
}
]
可以看到获取的注册信息还是很全面的。
最后说一下,movie工程接入Eureka Server的步骤就不再赘述了,因为是和user工程一样的(引入依赖,添加eureka client配置,添加application name)。配置完注册信息之后,重启所有项目,在Eureka Server首页看到两个项目都被注册进来就算成功了:
至此,有关Eureka的重要知识点都介绍完了。
那么我们的问题其实还没有解决,movie工程如何调用Eureka Server注册的user应用信息进行服务的请求呢?下一篇我们继续来学习。
本部分参考源码下载:https://download.csdn.net/download/u013517797/11267033
参考:《51CTO学院Spring Cloud高级视频》
http://www.likecs.com/show-27354.html
https://www.jianshu.com/p/d5943e303a1f
转载请注明出处:https://blog.csdn.net/acmman/article/details/94398375