注册中心 Eureka 源码解析 —— 调试环境搭建
本文主要基于 Eureka 1.8.X 版本
- 1. 依赖工具
- 2. 源码拉取
- 3. Eureka-Server 启动
- 3.1 MockRemoteEurekaServer
- 3.2 Eureka-Server war 包
- 3.3 Eureka-Server 直接启动
- 4. Eureka-Client 启动
1. 依赖工具
- Gradle
- JDK
- IntelliJ IDEA
2. 源码拉取
从官方仓库 https://github.com/Netflix/eureka.git Fork
出属于自己的仓库。为什么要 Fork
?既然开始阅读、调试源码,我们可能会写一些注释,有了自己的仓库,可以进行自由的提交。?
使用 IntelliJ IDEA
从 Fork
出来的仓库拉取代码。拉取完成后,Gradle
会下载依赖包,可能会花费一些时间,耐心等待下。
本文基于 master
分支。
3. Eureka-Server 启动
Eureka-Server 启动调试方式,有三种方式,我们来尝试每一种。
3.1 MockRemoteEurekaServer
com.netflix.eureka.AbstractTester
,测试抽象类,有如下实现子类:
使用任意一个子类的单元测试执行即可执行 Eureka-Server 逻辑的调试,这里以 com.netflix.eureka.resources.ApplicationsResourceTest
作为例子。
Debug 运行 ApplicationsResourceTest#testFullAppsGetJson()
单元测试。在方法执行前,ApplicationsResourceTest#setUp()
会运行,初始化 Eureka-Server 模拟环境,例如:
com.netflix.eureka.mock.MockRemoteEurekaServer
( 模拟 Eureka-Server )。
因为是模拟环境,对 Eureka-Server 的操作不是 Eureka-Client 请求 Eureka-Server 的方式,而是直接调用单元测试对应的方法。例如:
// ApplicationsResourceTest.java
@Test
public void testFullAppsGetJson() throws Exception {
Response response = applicationsResource.getContainers(
Version.V2.name(),
MediaType.APPLICATION_JSON,
null, // encoding
EurekaAccept.full.name(),
null, // uriInfo
null // remote regions
);
String json = String.valueOf(response.getEntity());
DecoderWrapper decoder = CodecWrappers.getDecoder(CodecWrappers.LegacyJacksonJson.class);
Applications decoded = decoder.decode(json, Applications.class);
// test per app as the full apps list include the mock server that is not part of the test apps
for (Application application : testApplications.getRegisteredApplications()) {
Application decodedApp = decoded.getRegisteredApplications(application.getName());
assertThat(EurekaEntityComparators.equal(application, decodedApp), is(true));
}
}
- 直接调用
ApplicationsResource#getContainers(...)
方法。
总结:这种方式,简单粗暴,容易上手。当然,它的缺点是模拟。刚开始调试 Eureka-Server 可以尝试这种方式。
3.2 Eureka-Server war 包
第一步,编译 Eureka-Server war 包。该步骤可能消耗漫长的时间,如果执行失败,请不断重试。命令如下:
cd eureka
./gradlew clean build
第二步,Debug 运行com.netflix.eureka.resources.EurekaClientServerRestIntegrationTest
任意单元测试方法。
总结:这种方式,编译的过程比较痛苦,不排除失败的可能性。每次增加对代码的注册后,都需要重新编译打包。因此不建议采用。那咋办呢?见第三种。良心如博主,赶紧关注博主的微信公众号:【芋道源码】。
3.3 Eureka-Server 直接启动
第一步,修改 EurekaClientServerRestIntegrationTest#startServer()
方法,解决第二种方式使用 war 包运行每次修改代码都需要重新编译的问题,实现代码如下:
// EurekaClientServerRestIntegrationTest.java
private static void startServer() throws Exception {
server = new Server(8080);
// TODO Thread.currentThread().getContextClassLoader() 获取不到路径,先暂时这样;
WebAppContext webAppCtx = new WebAppContext(new File("./eureka-server/src/main/webapp").getAbsolutePath(), "/");
webAppCtx.setDescriptor(new File("./eureka-server/src/main/webapp/WEB-INF/web.xml").getAbsolutePath());
webAppCtx.setResourceBase(new File("./eureka-server/src/main/resources").getAbsolutePath());
webAppCtx.setClassLoader(Thread.currentThread().getContextClassLoader());
server.setHandler(webAppCtx);
server.start();
eurekaServiceUrl = "http://localhost:8080/v2";
}
- 笔者不太熟悉 Gradle 的打包方式,使用
Thread.currentThread().getContextClassLoader().getResource()
方法,一直无法拿到路径,有知道的同学麻烦告知下。
第二步,Debug 运行com.netflix.eureka.resources.EurekaClientServerRestIntegrationTest
任意单元测试方法。TODO[0003]:Thread.currentThread().getContextClassLoader() 获取不到路径,先暂时这样;
总结:这种方式,完美。建议使用该方式调试。
4. Eureka-Client 启动
我们以 com.netflix.eureka.ExampleEurekaClient
为例子。
第一步,在 EurekaClientServerRestIntegrationTest#setUp()
方法末尾添加 Thread.sleep(Long.MAX_VALUE)
代码。
第二步,按照「 3.3 Eureka-Server 直接启动」方法启动 Eureka-Server。
第三步,将 EurekaClientServerRestIntegrationTest#injectEurekaConfiguration
复制到 ExampleEurekaClient 类里。
第四步,在 ExampleEurekaClient#main()
方法的第一行,添加 injectEurekaConfiguration()
代码。
第五步,Debug 运行 ExampleEurekaClient#main()
方法。
eureka-examples
模块还提供别的例子,可以逐个调试。
- TCP/IP(二)物理层详解
- JavaScript中的日期处理注意事项
- 概率论11 协方差与相关系数
- Mybatis传多个参数(三种解决方案)
- 语义化HTML:i、b、em和strong标签
- JSON入门指南--服务端处理JSON
- 纸上谈兵: 图 (graph)
- 纸上谈兵: 拓扑排序
- MyBatis Generator自动创建代码
- Maven(六)之依赖管理
- 细说log4j
- SEVERE: Error configuring application listener of class org.springframework.web.context.ContextLoade
- TCP/IP(一)之开启计算机网络之路
- JSON入门指南--客户端处理JSON
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- PUMA560机器人工具箱运动控制A:路径规划-运动学
- Android 3分钟带你入门开发测试
- Spring Boot 知识清单(一)SpringApplication
- Linux下的IO监控与分析
- pytorch+Unet图像分割:将图片中的盐体找出来
- html 用浏览器打开中文乱码解决方法
- SQLServer 数据库字符集、版本号sql语句查询语法
- chrome 浏览器自保留端口、安全端口有哪些?chrome不能访问某个端口的环境网址,但是其它的浏览器可以访问原因及解决办法。
- MySql 数据库 - 重置数据库、重置初始密码方法,数据库初始化方法,长时间不用忘记密码暴力解决方法
- MobaXterm工具连接Linux服务器入门使用手册,国产化泰山服务器连接工具使用演示
- Linux 服务器配置信息查询方法,国产化申威服务器配置信息查看演示
- 达梦数据库、oracle数据库如何判断指定表有没有建立索引?对应的表有没有索引查询方法
- Linux服务器运行sh文件提示权限不够解决方法?飞腾服务器Permission denied问题授权方法
- 不支持图形化界面的Linux系统如何显示图像化界面?飞腾服务器显示图像化界面方法,DISPLAY environment variable is undefined问题解决方法
- 一分钟学Python| Python的函数(上)