关于visual-studio-code:和-project-文件说再见-VS-Code-Java-110-背后的故事

114次阅读

共计 3344 个字符,预计需要花费 9 分钟才能阅读完成。

Language Support for Java 1.1.0 版本蕴含了一项重要更新:当初插件在导入新的 Java 我的项目时,我的项目元数据文件(.project,.classpath,settings 等)默认将不再生成于我的项目门路下。这一问题 自 2018 年被记录至今已有超过三年的工夫。本文旨在记录并分享咱们解决这一问题的过程和最初的解决方案。

悬在头顶的“达摩克利斯之剑”

随着 VS Code Java 的性能逐步丰盛,用户数量也在稳步回升。然而因为 Java 插件在导入我的项目时,会在我的项目目录下生成元数据文件的问题,咱们失去了不少的 1 星差评。能够预感,随着用户基数减少,因这一问题而造成的差评数量也会减少。这就如同一把悬在咱们头顶的“达摩克利斯之剑”,如果不及时解决,问题随时都有可能暴发。

其实这并不是咱们产品组不想彻底修复这一问题,根本原因须要从 Java 语言服务的架构说起:

VS Code Java 我的项目背地所采纳的 Java 语言服务的正式项目名称是 Eclipse JDT Language Server™,由微软和红帽联手开发。在下面的我的项目架构图中能够看到,咱们在实现中复用了 Eclipse 的一些模块,而这些主动生成的元数据文件也正是由其中一些上游模块所产生。在 Eclipse 的讨论区中能够找到一条相干的探讨帖子。这条帖子的创立工夫甚至能够追溯到 2004 年。因为在实现时,这些元数据文件的门路就曾经作为常量被硬编码在了代码里,这些常量又被各个不同的 Eclipse 模块甚至是插件援用,经久不息下来这一问题从某种意义上曾经成为了“历史包袱”。

思考到扭转上游模块的行为蕴含了太多的未知和不确定性,在过来咱们尝试给用户提供一些变通方法,比方让这些元数据文件在 VS Code 的文件浏览器中暗藏,并疏导用户将他们增加至 .gitignore 当中。但从用户的反馈来看,这些形式并没有让用户感到称心。为了可能彻底解决这个曾经困扰了咱们以及用户三年多之久的“顽疾”,咱们在往年下半年决定再做一次尝试,心愿能将其“根治”。

计划一:应用 Symbolic Link(失败)

咱们最先想到的办法是应用 Symbolic Link。在导入我的项目时,能够将被导入的我的项目通过 Symbolic Link 的形式链接到一个用户看不到的中央,从而让元数据文件生成在链接后的门路下。但很快这一计划就遇到了问题——在某些操作系统下创立 Symbolic Link 须要特定的权限,否则会抛出 FileSystemException,这显然不是咱们想要的成果,因而这个计划马上被否决了。

计划二:应用 Eclipse Linked Resources(放弃)

和 Symbolic Link 的思路相似地,咱们还能够抉择应用 Eclipse Linked Resources:

Linked Resources: Linked resources are files and folders that are stored in locations in the file system outside of the project’s location.

上文是 Linked Resources 的一段官网定义,它能够作为我的项目的一部分,但又容许存储在我的项目门路之外的其余地位。在 VS Code Java 中,咱们对于 Unmanaged Folder(无构建零碎的我的项目),就是通过 Linked Resources 机制将这些元数据文件暗藏的,它的实现原理如下图所示:

能够看到我的项目的理论门路放在了 Language Server workspace storage 中,用户通常并不通晓这一门路,同时在 .project 文件里咱们定义了 Linked Resources 的指标门路,也就是用户在 VS Code 关上的文件夹地位,它作为我的项目的一部分,会像其余我的项目一样参加到构建过程当中,其开发体验是相似的。

雷同的原理能够利用到 Maven 我的项目和 Gradle 我的项目的导入过程当中来解决这一问题,因而,咱们在 M2E 模块上进行了一些试验。M2E 模块在 Java 语言服务中负责 Maven 我的项目的导入,通过改变模块中的相干代码,并利用 Linked Resources 机制就能够将元数据文件生成到我的项目门路之外的中央。

最终的试验后果是可行的,然而这套计划的毛病也非常明显:

  • 改变较大:须要改变的代码散落在整个模块的不同文件中(大概十几处),同时因为代码规模较大,没有方法在短时间内确定这些改变是否是齐备的。
  • 对上游模块不通明:因为多了一层 Linked Folder,这会让 Java 我的项目视图在展现我的项目构造时,多出一层代表了 Linked Folder 的目录构造。在 Java 我的项目视图的实现中须要减少一些额定的管制逻辑,让我的项目构造的展现和失常我的项目一样。
  • 可行性未知:对于 Maven 和 Gradle 构建零碎的反对模块 M2E 和 Buildship 都是上游我的项目,这一概念是否被驳回承受是个未知数。
  • 扩展性差 :如果要反对一套新的构建零碎,须要将相似的逻辑再实现一遍。
    思考到上述起因,团队在通过探讨之后决定临时放弃 Eclipse Linked Resources 计划,并持续寻找更优的解决办法。

发现“银弹”

放弃第二套计划还有另一个起因:Eclipse 自公布至今二十载,在保障稳固运行的同时,能够一直地减少新的性能且提供了杰出的拓展能力,在这背地肯定蕴含了优良的架构设计和可拓展性。直觉上让咱们感觉应该还会有更优雅的解决办法。

因而,这一次咱们间接从 Eclipse 底层文件系统动手剖析,并最终发现了一枚解决问题的“银弹”:File System Provider 和 FileStore(注:尽管在软件工程畛域,人们的共识是没有银弹,不过对于这一特定的问题,咱们的确找到了一种比拟“奇巧”的解决办法)。

Eclipse 工作空间结构与 FileStore

Eclipse 在运行过程中会为整个工作空间保护一颗树形构造,树的节点代表了文件系统中的文件或目录,同时还保留了文件的一些重要信息,如批改工夫等。

Eclipse 底层通过 FileStore 类将这些节点和文件系统中的文件进行关联。FileStore 类还有一个重要个性:如果映射的对象是单个文件,那么 FileStore 还会负责提供这一文件的输入输出流。

这一个性为问题的解决带来了十分重要的思路:只有可能将元数据文件的输入输出流重定向到我的项目目录之外的地位,问题兴许就能得以解决。带着这个假如,咱们又发现了另一个要害线索:File System Provider。

计划三:File System Provider

File System Provider 是 Eclipse 平台对外开放的一个扩大点,它容许开发人员实现一个 Eclipse 文件系统接口(org.eclipse.core.filesystem.IFileSystem),并将其注册到扩大点上,用以解决具备特定 URI scheme 的文件申请。

于是咱们从 File System Provider 这一拓展点动手,继承并笼罩了 Eclipse 默认解决 URI scheme 为 file 的文件系统,通过覆写其中的一些办法,让文件系统在解决元数据文件时,将文件门路重定向到我的项目门路之外的中央进行读写。相比于计划二,这一套计划的长处在于:

  • 对其余模块齐全通明,根本不须要进行批改就能失常工作,这同时还意味着较好的拓展性。
  • 代码量很小,最终的实现,算上 JavaDoc 和正文,一共只有 300 行左右。

当然这个计划也并非完满,因为它要求其余模块通过 Eclipse 提供的 API 进行对元数据文件的读写操作。咱们在实现过程中就发现上游 Buildship 在解决元数据文件时间接通过 JDK 中的文件 I/O API 进行读写,为此咱们提交了一份变更申请将相干操作迁徙到了 Eclipse API 上。

总结

在衡量了利弊之后,咱们最终选取了第三套计划并解决了这一困扰了 VS Code Java 用户三年多工夫的问题。尽管最终的实现并不简单,但探寻答案的过程却十分具备戏剧性。

最初特别感谢 Eclipse Platform 我的项目成员 Mickael Istria 以及 Alexander Fedorov。在问题探讨的过程中他们给予了十分有用的倡议,对问题的解决起到了十分要害的作用。

正文完
 0