IDEA或Eclipse中编译调试ElasticSearch源码

对于想深入学习ES的人来说,编译源码,从而方便的进行阅读、调试是必不可少的。这方面的文章也不少,我尝试过几个,但多多少少都碰到了一些问题。最后参考官方的一篇博客编译成功了,可以正常的调试代码,且步骤简单。原文也不长,英文能力还行的可以直接阅读原文: How to Debug Elasticsearch Source Code in IntelliJ IDEA
。这里我简单总结并扩展一下,也支持Eclipse,并说明一下实际操作中要注意的细节。

关于JDK版本

ES是Java开发的,所以编译的时候肯定是需要JDK的。但需要注意,ES运行所需的JDK版本和编译所需的JDK版本要求是不一样的。运行ES,一般JDK 1.8(Java 8)就可以了(而且推荐该版本),而且从ES 7.0版本开始,默认下载的安装包里面已经集成了JDK。但是编译ES可不行,我编译ES 6.4版本的时候,需要的JDK版本是10,编译6.6版本的时候,需要的JDK版本已经是11了。所以,编译时所需要的JDK版本取决于你想编译的ES版本,源码根目录的
CONTRIBUTING.md

文件中贡献代码部分一般会指出编译所需的JDK版本(并且还有很多其它有价值的信息,比如如何使用Eclipse或者IDEA进行源码开发、编译、调试,建议看一下)。另外如果JDK版本不对,编译的时候会有错误信息提示。反正编译完之后,我的电脑上面现在已经装了JDK 1.8、JDK 9、JDK 10、JDK 11四个版本了,需要哪个用哪个。

这里以原文中的ES 6.6版本为例进行说明。ES 6.6版本编译依赖于JDK 11(必须),另外有些代码模块依赖于JDK 9,但这部分代码非必须,所以建议也安装好JDK 9,并为其设置环境变量 JAVA9_HOME
,编译时会通过该环境变量找JDK 9. 但JDK 9并非强制,如果你没有,编译的时候也不会报错,只会出几个警告。
最后贴上我的JDK环境变量的配置:

export JAVA8_HOME=$(/usr/libexec/java_home -v 1.8)    # 可选。如果是Linux或者Windows,将命令换为JDK的真实路径
export JAVA9_HOME=$(/usr/libexec/java_home -v 9)  # 可选
export JAVA10_HOME=$(/usr/libexec/java_home -v 10)   # 可选
export JAVA11_HOME=$(/usr/libexec/java_home -v 11)    # 必须
export JRE_HOME=$JAVA_HOME/jre
export CLASSPATH=.:$CLASSPATH:$JAVA_HOME/lib:$JRE_HOME/lib
export PATH=$PATH:$JAVA_HOME/bin:$JRE_HOME/bin

// 运行的时候使用Java 8(ES会读取该环境变量)
export RUNTIME_JAVA_HOME=$JAVA8_HOME    # 可选

1, 下载源码(这一步对于网络不好的人会很漫长),然后切换到自己想要的分支,这里使用6.6分支:

git clone https://github.com/elastic/elasticsearch.git
cd elasticsearch 
git checkout --track origin/6.6

2, 生成IDE所需要的文件:

// Eclipse
./gradlew eclipse

// IDEA
./gradlew idea

3, 把代码导入到Eclipse或者IDEA中:

// Eclipse
File: Import: Existing Projects into Workspace -> 选择ES源码目录
-> Search for nested projects

// IDEA
File->New Project From Existing Sources -> 选择ES源码目录
-> Import project from external model->Gradle

导入后,会自动开始编译,这又是一个很漫长的过程。这里可以做一点优化,修改一下根目录下的build.gradle文件:

// common maven publishing configuration
allprojects {
  group = 'org.elasticsearch'
  version = VersionProperties.elasticsearch
  description = "Elasticsearch subproject ${project.path}"

    // 增加下面部分
  repositories {
      google()
      jcenter()
      // maven库
      def cn = "http://maven.aliyun.com/nexus/content/groups/public/"
      def abroad = "http://central.maven.org/maven2/"
      // 先从url中下载jar若没有找到,则在artifactUrls中寻找
      maven {
        url cn
        artifactUrls abroad
      }
  }
}

4, 启动调试,以下命令会启动一个ElasticSearch实例,并且支持远程调试:

./gradlew run --debug-jvm

启动的ES实例的配置、数据等在 /distribution/build
目录。该命令执行后,会有一个短暂的编译过程,输出如下:

~/Elastic/ES/source/elasticsearch(6.6*) » ./gradlew run --debug-jvm                          
Starting a Gradle Daemon (subsequent builds will be faster)

> Configure project :benchmarks
=======================================
Elasticsearch Build Hamster says Hello!
  Gradle Version        : 5.1.1
  OS Info               : Mac OS X 10.14.6 (x86_64)
  JDK Version           : 11 (Oracle Corporation 11.0.3 [Java HotSpot(TM) 64-Bit Server VM 11.0.3+12-LTS])
  JAVA_HOME             : /Library/Java/JavaVirtualMachines/jdk-11.0.3.jdk/Contents/Home
  Random Testing Seed   : 416BC82E9B34077D
[elasticsearch] Java HotSpot(TM) 64-Bit Server VM warning: Option UseConcMarkSweepGC was deprecated in version 9.0 and will likely be removed in a future release.

> Task :distribution:run#start
Running elasticsearch in debug mode, suspending until connected on port 8000

[elasticsearch] Listening for transport dt_socket at address: 8000
 98% EXECUTING [2m 49s]
> :distribution:run#start

看到这个输出后,对于IDEA,从菜单中选择: Run
-> Attach to Process…
,选择类似这样的进程:” node0/elasticsearch-/data (8000)
“。ES的启动类是 org.elasticsearch.bootstrap.Elasticsearch
,可在其main函数中打个断点,这样就能停住程序了。

其实整个环境搭建过程在ES源码目录下的
CONTRIBUTING.md


TESTING.asciidoc

文件中都已经说得很细了,以前就觉得elastic公司的产品文档写的非常好,比如ElasticSearch、Filebeat、Logstash等产品,现在看来,源码的文档也是非常棒,值得学习。正如有人是这样形容代码文档的( 老司机们发表下感受
):

Documentation is like sex; when it's good, it's very, very good, and when it's bad, it's better than nothing.

环境只是手段,阅读源码才是目的,万里长征第一步。最后借用Linus的一句话来结束本文:

Read the Fucking Source Code(RTFSC)。

注:原话出自 这里
(google group),本意大致是要表达”仔细阅读源代码后再向写代码的人提问题,否则无法进行有效的沟通“。