Eclipse平台技术综述
本文的使用遵循Eclipse Public License 1.0 (EPL).
翻译:土豆爸爸
摘要
Eclipse平台的设计目的是建立一个集成开发环境(IDE)以及其它任意的工具。本文是对Eclipse平台的一般性技术的介绍。第1部分展示了它的技术架构,第2部分展示了Eclipse平台如何被用于构建Java开发环境。
2001年7月17日
修订历史
1.0 2001年7月17日 Jim des Rivieres (IBM) 原版.
2.1 2003年2月1日 Jim des Rivieres (IBM) 更新至Eclipse 2.1.
3.1 2006年四月9日 Wayne Beaton (The Eclipse Foundation) 更新至Eclipse 3.1.
当人们谈到Eclipse,他们通常是指Eclipse软件开发套件(SDK),它既是主流的Java集成开发环境(IDE),也是一个开发基于Eclipse平台产品的最好的工具。Eclipse SDK作为Eclipse家族的核心部件,包括平台(Platform) 、Java开发工具(JDT)以及插件开发环境 (PDE)。
从整体来讲,Eclipse平台包含了构建一个IDE所需的所有功能。然而,Eclipse平台本身是由部件组成的,通过使用这些部件的一个子集,可以构建任意的应用程序。Eclipse富客户端平台(RCP)就是这样一个子集。图1 中显示了Eclipse平台中的一些部件,其中加亮的部件组成RCP(实际上还有许多其它的部件)。
Eclipse平台不仅是构建开发环境的基础,它还是构建任意工具和应用程序的基础。RCP被用于构建与软件开发无关的工具和应用程序,例如在银行、汽车、医疗、太空探索等领域。正如“富客户端”所指的,Eclipse RCP是一个用于构建应用程序的卓越的平台,应用程序与应用服务器、数据库以及其它后台资源协作,为用户提供了了丰富的桌面体验。
Eclipse平台一个关键的优点在于,把它作为一个集成点使用。基于Eclipse平台的工具和应用程序,可以与其它用Eclipse平台编写的工具和应用程序集成。当向Eclipse平台添加Java开发组件时,它就变成一个Java IDE;当向Eclipse平台添加C/C++开发组件时,它就变成一个C/C++ IDE。如果同时添加这两套组件,那么它既是Java开发环境,又是C/C++开发环境。Eclipse平台将各种工具集成到一个单独的产品中,为用户提供了丰富的、一致性的体验。
集成同样也扩展到富客户端。一个组织可以将应用程序分配给不同的开发团队,然后使用Eclipse RCP集成。这并没有使开发大型应用程序变得平凡,但它使集成变得更加简单。
可能Eclipse平台提供的最明显的事情是一个托管的窗口系统。用户界面组件是这其中的一部分(包括输入框、按钮、表格和树视图),还有很多其它的东西。平台提供了窗口生命周期的管理,停靠视图和编辑器,提供菜单和工具条,以及拖放功能。
图2显示了主工作台窗口的截屏,其中包含了Eclipse平台里一些通用部件。
导航视图( 图2 , 左上)显示了用户工作空间里的文件;任务视图(右下)显示了to-do列表;大纲视图(左下)显示了所编辑文件的内容大纲(对文本文件不可用)。
尽管Eclipse平台具有许多内置的功能,其中大部分功能都是非常通用的。它接受其它的工具来扩展这个平台,或操作新的内容类型,或为已有内容类型提供新的功能,或将通用的功能应用于特定的方面。
Eclipse平台是建立在发现、集成以及运行模块的机制之上的。这里的模块被称为“插件(plug-in)“,它在 OSGi规范中被称为bundle。工具提供商编写了一个工具,作为一个独立的插件对工作空间中的文件进行操作,并在工作台中提供工具特有的用户界面。当平台启动时,在用户面前展现的是一个由各种插件组成的集成开发环境(IDE) 。用户体验的质量取决于工具是如何集成到平台中的,以及各种工具之间如何协同工作的。
Eclipse平台(或在不产生混淆时简称为“平台”)被设计和构建以满足以下需求:
-
支持各种应用程序开发工具的构建。
-
支持各种工具提供商,包括独立软件制造商(ISV)。
-
提供操作任意内容类型的工具(例如, HTML, Java, C, JSP, EJB, XML和GIF)。
-
简化不同内容类型和工具提供商之间的无缝集成。
-
支持GUI和非GUI应用程序开发环境。
-
在各种操作系统上运行,包括Windows LinuxTM, Mac OS X, Solaris AIX和HP-UX。
-
利用流行的Java编程语言编写各种工具。
Eclipse平台的主要角色是为工具提供商提供一套使用和遵循的机制,使各种工具能够无缝地集成。这些机制体现在明确定义的API、接口、类和方法。平台还提供一些有用的构建模块和框架,以方便新工具的开发。
图3 显示了Eclipse平台中的主要部件和API。
一个插件(plug-in)是Eclipse平台中的最小功能单元,它可以被独立的开发和发布。通常一个小工具可能只写一个插件,而一个复杂的工具将它的功能分割成多个插件。除了一个很小的内核,所有的Eclipse平台的功能都位于插件中。这个内核被称为平台运行时系统(Platform Runtime)。
插件是用Java编写的。一个典型的插件由以下内容组成:JAR中的Java代码、一些只读文件和其它资源(例如图片、web模板、消息资源文件、本地类库等)。一些插件不包含任何代码,例如一个插件提供HTML网页形式的在线帮助。一个插件的代码和只读文件位于文件系统的中的一个目录里,或位于服务器的根URL下。这种机制可用于为需要国际化的插件提供不同的语言包。
每个插件都有一个插件清单,用于声明它与其它插件之间的连接关系。这种连接系统模型很简单:一个插件可以声明任意数量的命名扩展点,以及任意数量的对其它插件中的扩展点的扩展。
一个插件的扩展点可以被其它插件扩展。例如,工作台插件声明了一个用于首选项的扩展点。任何插件都可以通过声明对这个扩展点的扩展以提供它们自己的首选项。
一个扩展点可以有一个相应的API接口。其它的插件通过扩展这个扩展点来实现该接口。任何插件都可以定义新的扩展点、提供新的API给其它插口使用。
当启动时,平台运行时系统发现可用的插件集合,读取它们的清单,并在内存中建立一个插件注册表。平台通过名称来匹配扩展和相应的扩展点声明。当出现问题时,会被检测到,并写入日志,例如扩展一个不存在的扩展点。插件注册表可以通过平台API获取。在启动之后也可以添加、替换和删除插件。
一个插件的清单由几个文件表示。manifest.mf文件是一个OSGI bundle清单,它描述了插件间运行时的依赖关系;plugin.xml是一个XML文件,它描述了扩展和扩展点的信息。一个扩展点可以声明用于扩展的XML元素类型。它允许提供扩展的插件向声明扩展点的插件提供任何所需要的信息。而且,扩展和扩展点的信息可以直接从插件注册表中获取,不需要激活提供扩展的插件或加载它的任何代码。当使用一个安装有大量插件的系统时,用户可能只需要其中的一部分插件,这一点就显得尤为重要。在代码被加载之前,插件只占用很少的内存和启动时间。使用基于XML的插件清单,可以更容易地编写支持创建插件的工具。Eclipse SDK中包含的插件开发环境(PDE)就是这样一个工具。
一个插件在它的代码真正需要运行时被激活。一旦被激活,插件使用插件注册表来发现和访问对它的扩展点的扩展。例如,声明首选项扩展点的插件可以发现所有其它插件提供的扩展,并访问它们的显示名称来构建一个首选项对话框。这只需从注册表中获取这些信息,不需要激活任何提供扩展的插件。当用户从列表选择一条选项时,相应的插件才被激活。以这种方式激活插件不是自动发生的;有一些API方法可用于显式地激活插件。插件一旦被激活,它就一直保持激活状态,直到取消激活或关闭平台。每个插件都有一个子目录,可以在里面存储插件特有的数据;这种机制允许插件在不同时刻运行时传递一些重要的状态数据。
平台运行时系统声明了一个专门用于应用程序的扩展点。当启动一个平台实例时,应用程序的名称通过命令行指定;声明该应用程序的插件被首先激活。
通过预先确定的可用的插件集合,通过不需要激活就可以在插件间交换信息,平台可以为每个插件提供它们所处环境的丰富的信息。 这个环境在平台运行时不能改变,所以不需要使用复杂的生命周期事件通知插件环境的变化。这也避免了冗长的启动次序,因为不可预测的插件启动次序常常是错误的来源。
Eclipse平台是通过调用单个标准Java虚拟机来运行的。每个插件都拥有自己的Java类加载器,它只负责加载插件自身的类和资源。每个插件显式地声明它所依赖的其它插件,可以访问其它的插件中的类,并控制公共类和接口的可见性。这些信息在插件清单文件中声明;可见性规则在运行时由插件的类加载器进行限制。
插件机制也用于Eclipse平台自身的划分。实际上,平台插件划分为工作空间、工作台以及其它。即使平台运行时系统本身也有自己的插件。平台的非GUI配置可以简单地去掉工作台插件以及依赖于它的插件。
Eclipse平台的更新管理器下载并安装新的特征(feature)或更新已有的特征(特征是一组相关的插件,它们被同时安装或更新)。更新管理器构造一个新的可用插件的配置,在下次Eclipse平台启动时生效。如果对安装或更新的结果不满意,用户可以回滚到前一个配置。
Eclipse平台运行时系统还提供一个用于动态扩展对象的机制。一个实现了IAdaptable接口的类声明它的实例对第三方的行为扩展开放。可以查询一个可适配的实例,用作一个实现一个接口或类的适配器对象。例如,工作空间资源是可适配的对象;工作台为资源添加适配器以提供合适的图标和文本标签。任何一方都可以通过注册适当的适配器工厂向可适配对象的已有类型(类和接口)添加行为。同一个可适配的对象可以被多方独立地扩展,分别用作不同的目的。当请求一个给定接口的适配器时,平台识别并调用相应的工厂来创建它。这种机制只使用可适配对象的Java类型,并不增加这个可适配对象的内存。任何插件都可以利用这种机制向已有的可适配对象添加行为,定义可适配对象的新的类型提供给其它插件使用或扩展。
各种插入到Eclipse平台中的工具都可以对用户工作空间里的文件进行操作。工作空间由一个或多个顶级项目组成,每个项目映射到文件系统中用户指定的目录。工作空间里不同的项目可以映射到不同的文件系统目录或硬盘,尽管在缺省情况下,所有项目都映射到工作空间目录下子目录。
项目类型(nature)机制允许一个工具标记一个项目,赋予它一个特殊的个性或类型。例如网站类型标记一个项目包含静态的网站内容,Java类型标记一个项目包含Java程序的源代码。如果需要,插件可以声明新的项目类型。这样,不同工具就可以共享一个项目,而且工具之间不需要知道对方。
每个项目包含了用户创建和操作的文件。工作空间里所有的文件都可以被操作系统中的程序和工具访问。与平台集成在一起的工具可以通过API处理工作空间资源(项目、文件、文件夹的统称)。工作空间资源由可适配对象来表示,所以它们的行为可以被多方扩展。
为了减少意外丢失文件的风险,底层的工作空间历史机制跟踪所有被修改或删除的文件的以前的内容。用户可以通过基于空间或基于时间的首选项来控制历史的管理。
工作空间提供了标记机制对资源进行注释。标记用于记录不同的注释,例如编译错误消息,to-do列表项、书签、查询提示以及调试断点。标记机制是开放的。插件可以声明新的标记子类型,并控制它们是否在不同运行期间保存。
平台提供一个通用的机制允许一个工具跟踪工作空间资源的变化。通过注册一个资源变化监听器,工具可以接收到所有资源创建、删除、修改的通知。平台将延迟事件通知,直到批量资源操作完成。事件以资源树差异的形式报告整个批量操作的影响。资源差异还提供有关标记修改的信息。
资源树差异对于那些显示资源树的工具特别有用和有效,因为每个差异点指出工具应该在哪里添加、删除或刷新屏幕控件。此外,因为一些半独立的工具可能正在对一个项目的资源进行操作,这种机制允许一个工具检测另一个工具的对特定文件、文件类型的活动。
象编译器和链接检查器这样的工具,它们必须对数以千计的独立文件进行分析和转换。平台提供了一个增量项目构建框架;增量构建的输入是一个资源树差异,它包含了从上次构建以来的净资源差异。精密的工具可以使用这个机制提供可扩展的解决方案。
平台允许相同的项目注册多个不同的增量项目构建器,提供不同的方式来触发项目范围和工作空间范围的构建。如果设置了工作空间自动构建,当每个资源发生修改后都会触发自动构建。
工作空间保存-恢复过程是开放的。一个两阶段的保存过程确保各种插件重要的状态以原子操作的形式写入硬盘。在一个并发的会话中,当某个单独的插件重新激活并重新加入到保存-恢复过程中时,将传递给它一个工作空间范围的资源差异,这个差异描述从它参与上次保存到当前的净资源差异。这允许插件结转它以前保存的状态,根据资源的变化作必要的调整。
Eclipse平台用户界面是围绕着工作台来建立的,工作台提供了整个的结构,为用户提供一个可扩展的用户界面。工作台API和实现是建立在以下两个组件的基础上:
-
SWT - 一套与本地窗口系统集成的组件和图形库,具有与操作系统无关的API。
-
JFace - 一个使用SWT实现的用户界面组件,用于简化常见的用户界面编程任务。
标准窗口组件套件(SWT)为窗口组件和图形提供了一套通用的、独立于操作系统的API,但它以与底层的本地窗口系统紧密集成的方式实现。整个的Eclipse平台用户界面以及其它工具插件使用SWT来向用户展示信息。
在窗口组件的设计上,可移植的组件与本地窗口系统的集成是一个由来已久的问题。Java的抽象窗口套件(AWT)提供了低级组件,如列表、文本域和按钮,但没有高级组件,如树和富文本。AWT组件直接使用底层的本地组件实现。只使用AWT来构建用户界面意味着只能使用所有操作系统共有的组件进行编程。Java Swing套件通过模拟树、表格和富文本等组件解决了这一问题。Swing还提供了look and feel模拟层,试图使应用程序看起来象底层的本地窗口系统一样。然而,模拟的组件的look and feel总是落在本地组件的后面,使用模拟组件的用户界面通常总让人感到不同,使它难以构建商品化的软件,特别是专门针对一个本地窗口系统时。
SWT通过定义一套通用的API来解决这一问题,这些API在很多被支持的窗口系统中都可以使用。对每个不同的本地窗口系统,SWT尽量使用本地组件实现;如果没有对应的本地组件,SWT会提供适当的模拟。通用的低级组件,例如列表、文本域和按钮,都已实现本地化。但一些常用的高级组件可能需要在一些窗口系统中进行模拟。例如,SWT工具栏组件在Windows上以本地工具栏组件实现,在Motif®上是模拟实现。这种策略允许SWT在所有环境中维护一个统一的编程模型,并且在最大程度上呈现本地窗口系统的look and feel。
当一个特定的底层窗口系统提供一个特有的重要的特性,而其它窗口系统没有时,SWT还提供了本地窗口系统特有的API。Windows ActiveX®就是其中之一。Window系统特有的API放在一些被适当命名的包,表示它们是不可移植的。
与底层本地窗口系统的紧密集成不仅仅体现在look and feel上。SWT还和本地桌面特征进行交互,例如拖放操作,和底层窗口系统的外观主题API进行交互。(与Java AWT相比,AWT将窗口系统特有的差别放在Java本地方法的C代码实现里。)由于没有特有逻辑以本地方式实现,SWT全部是由Java代码实现的。然而,Java代码看起来对本地操作系统开发人员并不陌生。任何Windows程序员都会很快熟悉Windows的SWT的Java实现,这是因为它是由对Windows API的调用组成,他们在C语言编程中已经知道了。同样,对Motif程序员看Mofit的SWT的实现也是一样。这种策略大大地简化了实现、调试和维护SWT的工作量,因为它允许这些有趣的开发都可以用Java完成。当然,SWT的普通用户并不关心这些,因为这些本地化的工作完全隐藏在独立于窗口系统的SWT API之后。
JFace是一个用户界面套件,包含了很多处理通用界面编程任务的类。JFace是在API和实现上都是独立于窗口系统的,它被设计用一和SWT一起工作,而不是隐藏它。
JFace包含了常用的界面组件,例如图片和字体注册、对话框、首选项、向导框架以及用于长时间运行操作的进度报告。其中最令人感兴趣的是action和viewer。
Action机制允许用户不需要知道界面的情况下,独立地定义命令。一个action代表一个可以通过按钮、菜单或工具按钮触发的命令。每个action都知道自己关键的界面属性(标签、图标、工具提示等),这些属性用于构建适当的界面组件来表示该action。这种分离允许相同的action在界面的不同位置上使用,还意味着很容易修改界面中的action表示方式,而不需要修改action本身的代码。
Viewer是某些SWT组件基于模型的适配器。Viewer处理通用行为,比SWT组件提供更高层的语义。用于列表、树、表格的viewer支持使用客户域对象元素填充,并保持与域对象同步更新。这些viewer使用内容提供者(content provider)和标签提供者(label provider)。内容提供者知道如何将提供者的输入元素映射到viewer的内容,以及如何将域对象的修改同步到viewer。标签提供者知道如何为组件中显示的元素产生适当的字符串标签和图标。Viewer可以配置基于元素的过滤器和排序器。当发生选择或事件时,客户将以域元素的形式得以通知。Viewer的实现处理域元素与SWT之间的映射,必要时对元素的过滤视图进行调整,或重新排序。用于文本的标准viewer支持一些常见的操作,例如双击、撤消、着色以及根据字符索引或行号进行导航。文本viewer向客户提供了一个文档模型,管理从文档向SWT样式文本组件所需信息的转换。多个viewer可以打开同一个模型或文档;当模型或文档发生变化所有的viewer都会自动更新。
SWT和JFace是通用的界面套件,而工作台提供了Eclipse平台个性化的用户界面,提供了工具与用户进行交互的结构。工作台与Eclipse平台界面以及平台运行时用户看到的主窗口(见图2)是同义的。工作台API独立于SWT API,并且对JFace的依赖较少。工作台是用SWT和JFace来构建的,没有使用Java AWT和Swing。
Eclipse平台界面样式是基于编辑器(editor)、视图(view)和透视图(perspective)的。从用户的角度上看,工作台窗口由视图和编辑器组成。透视图体现在选择和安排屏幕上可见的编辑器和视图。
编辑器允许用户打开、编辑和保存对象。他们遵循打开-保存-关闭这样一个生命周期,这很象基于文件系统的工具,但紧密地集成在工作台中。当激活时,编辑器可以向工作台的菜单和工具栏提供action。平台提供了为文本资源提供了标准编辑器,其它插件提供更特殊的编辑器。
编辑器允许用户打开、编辑和保存对象。他们遵循打开-保存-关闭这样一个生命周期,这很象基于文件系统的工具,但紧密地集成在工作台中。当激活时,编辑器可以向工作台的菜单和工具栏提供action。平台提供了为文本资源提供了标准编辑器,其它插件提供更特殊的编辑器。
视图提供关于工作台正在处理的对象的相关信息。视图可以辅助编辑器提供关于正在编辑的文档的相关信息。例如,标准内容大纲视图显示了当前活动编辑器中的内容的大纲。一个视图还以通过提供当前选择对象的相关信息,来补充另一个视图的内容。例如,标准的属性视图显示了另一个视图选择的对象的属性。视图的生命周期比编辑器简单:在视图进行的修改(例如修改一个属性值)通常立即保存,修改立即反映到用户界面的相关部分。平台提供许多标准视图(见图2);其它一些视图由其它插件提供。
工作台窗口可以有多个独立透视图,在给定的时刻,只有一个可见。每个透视图都有自己的视图和编辑器,它们被安排(平铺、叠放、漂浮)显示在屏幕上(其中一些在给定时刻不可见)。在透视图中,同一时刻可以打开多个同类型的视图和编辑器。透视控制初始视图的可见性、布局以及action的可见性。用户可以快速切换不同的透视图,执行不同的任务,可以很容易地重新安排和自定义一个透视图,使之更适合于某个特殊的任务。平台提供了标准的透视图用于资源导航、在线帮助和团队支持任务。其它的透视图由其它插件提供。
工具按这种明确定义的视图-编辑器-透视图的方式集成到用户界面中。工作台中为工具提供以下扩展点:
-
添加新的编辑器类型。
-
添加新的视图类型。
-
添加新的透视图来安排新旧视图以满足新的用户任务。
平台的标准视图和编辑器就是采用这种机制提供的。
工具还中以为已有的编辑器、视图、透视图提供:
-
向已有的视图的本地菜单和工具栏添加新的action。
-
当已有的编辑器激活时,向工作台菜单和工具栏添加新的action。
-
向已有的视图和编辑器的弹出菜单添加新的action。
-
向已有的透视图添加新的视图、action集和快捷方式。
平台负责工作台窗口和透视图管理的各个方面。编辑器和视图在需要时自动被实例化,当不再需要时被清除。工具提供的action的标签和图标是在插件清单中列出的,所以工作台不需要激活插件就可以创建菜单和工具栏。直到用户试图使用插件提供的功能时,工作台才激活该插件。
一旦一个编辑或视图变成一个透视图的活动部件,它可以使用工作台服务来跟踪激活和选择。部件服务跟踪透视图中视图和编辑器的激活,向注册的监听器报告激活、取消激活事件。一个视图或编辑器可以向选择服务注册成为一个选择的来源。选择服务向所有注册的监听器提供选择变化的事件。例如,当前编辑或视图中选择的对象就是以这种方式通知属性视图的。
采用平台API以Java编写的工具可以与平台实现最高层次的集成。另一个极端是,从平台中启动外部工具,这些工具为了与用户交流必须打开他们自己的独立的窗口,必须通过底层的文件系统访问用户数据。因此,这种集成是非常松散的,特别是在用户界面层。在某些环境中,Eclipse平台还支持其它一些级别的集成:
-
工作台内建支持将一个OLE文档作为一个编辑器(只支持Windows)。这种方式提供了紧密的用户界面集成。
-
一个插件工具可以实现一个容器,作为Eclipse平台API到ActiveX控件的桥梁,这样就可以在编辑器、视图、对话框或向导中使用ActiveX控件。SWT提供了必要的低级支持。这种方式提供了紧密的用户界面集成。
-
一个插件工具可以使用AWT或Swing打开一个独立的窗口。这种方式提供了松散的用户界面集成,但允许用户界面之下的紧密集成。
Eclipse平台允许工作空间中的项目使用团队存储库进行版本和配置管理。平台提供了扩展点和存储库API,允许插入新的存储库。
一个特定的团队存储库提供的功能总是影响着用户的工作流程,例如,通过添加明显的步骤,用于从存储库中提取文件,用于将文件更新至存储库,以及用于比较文件的版本。不同的存储库对用户工作流程的影响程序不同。因此,Eclipse平台不干涉的视图的实现,允许每个存储库的提供者定义他们自己的工作流程,这样,已经熟悉某个团队存储库产品的用户可以很快掌握如何在Eclipse中使用它。平台提供了基本的钩子,允许团队存储库的提供者参于对项目中资源的操作。这些钩子对乐观模型和悲观模型都提供了很好的支持。在界面级别,平台为某些action、首选项和属性提供了占位符,留给团队存储库的提供者定义这些用户界面元素。还有一个简单的、可扩展的配置向导,使用户能够将项目与存储库关联起来,每个团队存储库的提供者可以使用用户界面元素扩展它,用于收集存储库特有的信息。
多个团队存储库的提供者可以在平台里和平相处。Eclipse平台包含了对CVS存储库的支持,可以通过pserver、ssh、extssh协议进行访问。
Eclipse平台帮助机制允许工具定义和提供一个或多个在线文档。例如,工具通常提供帮助风格的用户手册和独立于编程手册的API文档(如果有的话)。
帮助的原始内容是HTML文件。为了方便在线文档的导航,用一个单独的XML文件进行描述。这种分离允许已有的HTML文档直接组织到在线帮助中,而不需要进行编辑或重写。
这个附加的导航结构以主题树的形式表示在线帮助中的内容。每个主题,包括非叶主题,可以有一个到原始内容页面的一个链接。每个在线帮助可以有多个备用的顶级主题列表,允许相同的信息以不同的方式进行组织;例如,按任务或工具进行组织。
XML导航文件和HTML内容文件存储在插件的根目录或子目录中。小一点的工具通常将帮助文档作为代码放在同一个插件中。大的工具通常具有独立的帮助插件。平台使用它内部的文档服务器在文档网站里提供实际的网页。这个自定义的服务器允许平台解析特殊的插件内部的链接以及从ZIP文件中提取HTML页面。
当组织一个帮助系统时,只有关闭被编档的工具集合才能形成一个完整的主题树。在Eclipse平台中,工具集合是开放的,因此,帮助文档的结构需要模块化。平台帮助机制允许工具提供原始内容和主题集,并且指定在已有主题树的哪个位置插入它自己的主题。
正如第1部分所述,Eclipse平台本身是构建工具和应用程序的基础。插入到平台中的插件提供了特殊的能力,使它适合于开发特定类型的应用程序。这一部分是一个真实工具的案例,Java开发工具(JDT),它向平台添加了Java程序开发的能力。JDT包含在Eclipse SDK中。
在了解JDT后台是如何组织之前,我们先看一下JDT能做什么,它看起来是什么样子的。图4显示了当用户编写Java程序时工作台的样子。
JDT向Eclipse平台添加了Java IDE的能力(部分在图4中可以看到)。下面是这些特征的简要的总结:
-
Java项目
-
Java源代码文件(*.java)以传统的Java包目录形式放置在一个或多个源文件夹下面。.
-
相同项目、不同项目或工作空间外部的JAR库文件。
-
生成的二进制类文件(*.class)以包目录的形式放置在一个单独的输出文件夹下面。
-
无限制的其它文件,例如程序资源和设计文档。
-
-
浏览Java项目
-
以Java特定的元素进行浏览:包、类型、方法、域。
-
可以按包、超类型或子类型进行排列。
-
-
编辑
-
Java源代码编辑器。
-
关键字和语法着色(包括Javadoc注释中的)。
-
单独的大纲显示声明的结构(当编辑时自动更新)。
-
在边界上显示编译问题的标记。
-
在边界上显示声明代码范围的标记。
-
-
代码格式化
-
对编辑器选中的Java元素进行代码分析。
-
代码补全处理合法的方法、名称等。
-
为选中的Java元素在弹出窗口中显示API帮助信息。
-
自动地创建和组织导入声明。
-
-
重构
-
用于提升代码的结构而不改变它的行为。
-
提取方法。
-
安全地重命名方法,并且更新引用。
-
预览(以及否决)重构操作中某个单独的修改。
-
-
查找
-
查找包、类型、方法、域的声明或被引用的情况。
-
查询结果在查询结果视图中显示。
-
查询结果根据Java元素进行报告。
-
匹配部分在编辑器中加亮显示。
-
-
比较
-
对Java编译单元进行结构化的比较,显示单个方法的修改。
-
使用本地历史中的元素替换单独的Java元素。
-
-
编译
-
JCK兼容的Java编译器。
-
编译器生成标准的二进制*.class文件。
-
增量编译。
-
手工触发编译,或每次修改源代码时自动触发编译(例如,工作空间自动编译)。
-
编译问题在标准的任务视图中显示。
-
-
运行
-
在单独的Java虚拟机中运行Java程序。
-
支持多种类型的Java虚拟机(用户可选)。
-
控制台提供了stdout、stdin、stderr。
-
剪贴簿页面用于交互式的Java代码片断的执行。
-
-
调试
-
使用JPDA兼容的Java虚拟机调试Java程序。
-
查看线程和栈结构。
-
设置断点,单步执行方法的源代码。
-
查看和修改域和局部变量。
-
在栈结构的上下文中评估表达式。
-
当Java支持时,动态地重新加载类。
-
JDT是由一组插件来实现的,用户界面位于UI插件中,非UI的基础结构位于其它核心插件中。这种UI和非UI代码的分离,允许JDT核心基础结构可以在Eclipse平台无图形用户界面的配置中使用,可以在其它用到Java能力而不需要JDT界面的其它图形化工具中使用。
图5说明了JDT与平台间关键的连接。
在工作空间层,JDT定义了一个专用的Java项目类型,它用于将一个项目标记为Java项目。
每个Java项目都有一个专用的类路径文件(名称为.classpath),用于记录Java专用的信息。这些信息包括项目源文件夹的信息,预编译的JAR库文件以及用于存放编译生成二进制类文件的文件夹
Java类型为每个Java项目配置一个Java增量项目构建器,它调用内建的Java编译器。
当首次构建或全部构建时,Java编译器将项目源文件夹下的所有的Java源文件编译成相应的二进制类文件,放置到项目输出文件夹中。JDT为Java问题声明了一个新的标记。当编译器检测到错误时,它使用Java问题标记注释有问题的源代码。一个项目规定了它所依赖的JAR库文件。这允许JDT定向于各种Java运行时的配置,例如CLDC、J2SE和J2EE。
当编译器遇到每个源文件时,它向一个内存中的依赖图中添加信息。这允许项目的后续构建更有效地处理。工作空间增量项目构建框架维护了一个资源差异树,其中包含了自最后一次调用构建器以来的修改。当下一次调用Java增量项目构建器时,它使用这个资源差异树来确定需要重新编译的源代码集合,因为它们被修改、删除或添加。编译器使用它的依赖图来进一步扩大需要重新编译的源代码集合的范围。接着,编译器删除过时的类文件以及Java问题标记,对计算出的源代码子集进行编译。JDT参与工作空间的保存过程,所以依赖图可以存储在磁盘上,用于不同的会话期,否则,下一次会话时,需要全部编译来重新发现依赖图。即使项目包含成百上千的源代码,这种增量策略也允许JDT经常地运行构建,例如,在每次源文件保存操作之后。
Java模型提供了API,用于在Java元素树中导航。Java元素树以Java的元素类型来表示项目:
-
包片断的根对应于项目的源文件夹和JAR库文件。
-
包片断对应于一个包片断的根里面的特定包。
-
编译单元和二进制类对应于单个的Java源代码(*.java)和二进制类文件(*.class)。
-
各种类型的Java声明显示在编译单元或类文件中:
-
包声明
-
导入声明。
-
类和接口声明。
-
方法和构造函数声明。
-
域声明。
-
初始化器声明。
-
对于大多数Java工具(包括Java用户界面)而言,一个Java项目上通过Java模型导航和操作比在底层资源上导航更方便。Java元素使用可适配对象表示,所以其它部分可以扩展它们的行为。
Java项目的类路径文件和底层的资源定义了Java元素树。将Java元素树放在内存中是不切实际的,因为它比工作空间的资源树数目大一个数量级,并且需要读取和分析所有的Java源文件。相反,Java元素树的构建是在需要时逐步完成的。Java编译器分析单个的编译单元获取声明的结构。Java元素树维护一个内部的、限制大小的缓存,用于保存最近分析的编译单元。Java元素树向工作空间注册一个资源修改监听器,这样,当资源被删除和修改时,它可以删除过时的缓存项。Java元素树发布它自己的差异,这与工作空间资源树差异类似。
一个基于缓存的Java元素树对于简单的导航比较合适,但不能支持大范围的查找或其它需要横跨大量不同编译单元的声明访问。Java模型通过在磁盘上维护一个内部的索引来解决这一问题。索引由一些汇总项组成,汇总项将声明名称和引用名称关联到相应文件的路径。给定一个名称,这些索引可以有效地查找到包含它的文件。如果需要进一步地精确或者需要行号,这些文件可以被读取或分析。Java模型使用资源修改监听器来跟踪需要建立索引的文件。单个文件索引的建立是在一个低优先级的线程中执行的。
JDT的用户界面定义了一个Java透视图,用于开发Java代码。这个透视图包含了以下Java专用的特性:
-
包视图。
-
类型层次结构视图
-
创建Java元素的action。
-
Java编译器Java大纲视图。
包视图显示了Java项目中的编译单元或JAR库文件中的类文件。在树视图显示的元素和关系直接来自于Java模型。
与之相反,类型层次结构视图按Java语言中定义的超类型和子类型的关系显示类和接口。类型层次结构使用一系列的基于索引的Java模型查询,并结合分析相关的编译单元提取直接父类名称来构建的。视图中显示的元素直接来自于Java模型。
action触发向导,用于创建一个新的Java项目、包、类或接口。这些action都是在Java模型上进行操作的。
Java编辑器注册为编辑*.java类型文件的编辑器。这个编辑器与标准工作空间内容大纲视图协作,为当前声明结构提供了一个Java元素树。Java编辑器扩展了JFace文件viewer控件以实现以下特性:
-
分割 - 使用一个基于规则的扫描器,将Java代码和Javadoc注释分割成不同的区域。
-
关键字和语法着色 - 在每个不同区域应用着色规则,可视化地区分不同的元素。
-
边界注释 - 文本视图的边界里显示了行范围、问题标记以及调试断点。这些注释在编辑文本时自动调整。
-
格式化 - 控制自动地缩进、调整行内和行间的空白。
-
代码辅助 - 提供特定区域Java(或Javadoc)补全建议。这依赖于Java编译器的支持。
-
内容大纲 - 在编辑过程中更新。它作为一个背景活动周期性地执行。在内容大纲中的选择和操作立即反映到编辑器缓冲区中。
-
方法级的编辑 - 编辑器还可以只显示一个单独的方法(或其它类型的声明),而不是整个源文件。
重构操作,例如重命名,依赖于基于索引的Java模型查询以及特定的编译器支持来定位和重写受影响的部分。
工作台包含了运行和调试任意程序的菜单和工具栏,提供了通用的调试透视图。这个透视图包含了一个进程视图,显示出所有当前正在运行和最近终结的进程,还包含一个控制台视图,允许开发人员通过标准的输入和输出流与选择的正在运行的进程交互。
JDT提供了运行和调试Java程序的手段。它启动一个目标Java虚拟机在一个单独的进程中运行Java程序。JDT支持启动不同类型的Java虚拟机。其它工具可以通过JDT定义的扩展点,提供专用的启动程序。
剪贴簿页面表示为一个文本文件(类型为*.jpage),它通过一个知道如何运行Java代码片断的特殊的文本编辑器进行编辑。这涉及到将语句、表达式或声明嵌入到一个主类中,编译它并下载到一个运行的Java虚拟机,运行它,提取打印字串并在编辑器中显示。这个特性依赖于编译器的支持,但不需要目标Java虚拟机的支持。
当一个Java以调试模式启动时,调试视图显示了进程、线程以及栈结构。当调试器需要向用户显示源代码时,它使用工作台提供的机制打开一个编辑器。在单步执行的过程中,调试器指示编辑器哪一行需要加亮。其它调试专用的视图显示了断点列表、变量值、对象的域。断点用一个特殊类型的标记表示。
Java调试器可以与任何JDPA兼容的Java虚拟机一起工作。通过一个Java表达式解释器历遍表达式的抽象语法树,并执行标准的JDI调用,我们可以在当前运行方法的上下文中评估Java表达式。JDI操作透过目标Java虚拟机访问域或调用方法。如果Java虚拟机支持动态类重新加载,对正在运行的程序的修改可以立即被安装,这样,调试会话可以在修改的位置上继续执行。调试器注册了一个资源修改监听器,它可以发现项目输出文件夹中的哪个二进制类文件需要重新加载到目标虚拟机中。