注册中心 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 IDEAFork 出来的仓库拉取代码。拉取完成后,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 模块还提供别的例子,可以逐个调试。

原文发布于微信公众号 - 芋道源码(YunaiV)

原文发表时间:2018-02-05

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏运维前线

常用ansible命令

常用ansible命令 使用ansible-doc -l 查看具体模块的使用方法,这里举例常用的ansible简单用法 执行系统命令 [root@ansi...

2295
来自专栏转载gongluck的CSDN博客

学习GDB

1 简介      GDB(GNU Debugger)是GCC的调试工具。其功能强大,现描述如下:      GDB主要帮忙你完成下面四个方面的功能:     ...

3687
来自专栏xingoo, 一个梦想做发明家的程序员

Java程序员的日常——经验贴(纯干货)二

继昨天的经验贴,今天的工作又收获不少。 windows下编辑器会给文件添加BOM 在windows的编辑器中,为了区分编码,通常会添加一个BOM标记。比如...

2159
来自专栏Java3y

纳税服务系统一(用户模块)【简单增删改查、日期组件、上传和修改头像】

前言 为了更好地掌握SSH的用法,使用一个纳税服务系统来练手…..搭建SSH框架环境在上一篇已经详细地说明了。http://blog.csdn.net/hon_...

5819
来自专栏栗霖积跬步之旅

Could not resolve view with name '***' in servlet with name 'dispatcher'

今天在开发中遇到了一个问题,控制层使用的是SpringMVC框架。 @RequestMapping("historyDetail") priva...

29710
来自专栏崔庆才的专栏

是时候抛弃print了,开始体验下logging的强大吧!

2002
来自专栏阿杜的世界

RocketMQ学习-NameServer-1

NameServer在RocketMQ中的角色是配置中心,主要有两个功能:Broker管理、路由管理。因此NameServer上存放的主要信息也包括两类:Bro...

1223
来自专栏向治洪

Elcipse安装gradle插件

参考: http://www.gradle.org/docs/current/userguide/installation.html (1)下载Gradle ...

2078
来自专栏xingoo, 一个梦想做发明家的程序员

Spring MVC 基于Method的映射规则(注解版)

在Restful风格的web开发中,根据不同的请求方法使用相应的控制器处理逻辑成为核心需求,下面就看看如何在Spring MVC中识别不同的请求方法。 请...

2189
来自专栏开发与安全

gdb基础命令和常用操作补充

GDB是Unix下的一个程序调试工具,类似于windows下面的VC调试器,区别在于GDB采用全命令行控制。 使用GDB需要在编译时使用-g选项,gcc支持-...

2580

扫码关注云+社区