如何在 Eclipse PDE 中表达项目间依赖关系

Posted

技术标签:

【中文标题】如何在 Eclipse PDE 中表达项目间依赖关系【英文标题】:How to express inter project dependencies in Eclipse PDE 【发布时间】:2010-11-26 06:43:05 【问题描述】:

我正在寻找处理混合项目类型之间项目间依赖关系的最佳实践,其中一些项目是 Eclipse 插件/OSGI 捆绑项目(RCP 应用程序),而其他项目只是普通的旧 Java 项目(Web 服务模块)。很少有 Eclipse 插件依赖于 Java 项目。

我的问题是,至少在我看来,没有办法在 Eclipse PDE 环境中清晰地表达这种依赖关系。我可以让插件项目依赖于其他插件项目(通过Import-PackageRequire-Bundle 清单头),但不是普通的java 项目。

我似乎可以让项目声明对工作区中另一个项目的 jar 的依赖,但是这些 jar 文件不会被导出或启动配置拾取(尽管,java 代码编辑看到这些库就好了)。

“Java 项目”用于构建要部署在 J2EE 容器(目前为 JBoss 4.2.2)上的服务,并在某些情况下生成多个 jar - 一个用于部署到 JBoss ear,另一个用于客户端使用代码(RCP 应用程序)。

我们现在“解决”这个问题的方法是我们有 2 个额外的外部工具启动器配置 - 一个用于构建所有 jar,另一个用于将这些 jar 复制到插件项目。这可行(有点),但是“整个构建”和“复制 jars”目标会产生相当大的构建步骤,绕过整个 eclipse 增量构建功能并复制 jars 而不是仅仅引用我正在解耦依赖项信息的项目并要求进行相当大的工作空间刷新,这会像吃糖果一样消耗开发时间。

我想要的是一个更“自然”的工作空间设置,它可以管理项目之间的依赖关系并仅在需要时请求增量重建,能够在 RCP 应用程序插件中使用服务库中的客户端代码并且能够在需要的地方启动带有所有必要类的 RCP 应用程序。

所以我可以把蛋糕也吃掉吗;)

注意

需要明确的是,目前这不是关于依赖管理和模块管理,而是关于 Eclipse PDE 配置。

我非常了解 [Maven]、[Ivy] 和 [Buckminster] 等产品,它们解决了一个完全不同的问题(一旦我解决了工作区配置问题,这些产品实际上可以派上用场实现工作区并构建产品)

【问题讨论】:

【参考方案1】:

Eclipse 项目通过项目属性(依赖项目?)中的复选框相互依赖,这是 Eclipse 决定构建哪个项目的方式。您可以自行设置,但通常在您更改 Java 构建路径时设置。它将数据存储在 .project 文件 IIRC 中,因此一旦您浏览了 GUI 并查看了哪些更改,您就可以更灵活地应用其他文件。

但是,听起来您想混合搭配 Jars 和 Bundles。简单的方法就是将所有项目都视为 Java 项目。在 PDE 项目中,您实际上可以进入并调整 Java 构建路径;它会抱怨并说这不是正确的方法,但它可以让您拥有一个依赖于 Java 项目的 PDE 项目,而无需启动所有蓬松的 JAR。话虽如此,如果这种方法存在运行时问题,我也不会感到惊讶 - PDE 运行时可能不会这样看。

另一种方法是让您的 JAR 自己成为 PDE/OSGi 包。毕竟,OSGi 包只不过是一个 JAR,在 Manifest 中有一些额外的东西,它可以让您使用自动依赖管理轻松地开发和组装您的项目。这可能是最容易做到的,即使你并不真的需要清单出现在你的包中。但这样做意味着您的 PDE 应用程序可以采用更加模块化的方法交付,而不是根据需要将库嵌入每个插件中。

所以,PDE 可以生成 OSGi 包,这只是 JAR + Manifest 东西的另一个名称。您可以在其他环境中以完全相同的方式使用 JAR(例如,供您的 EAR 或其他客户端使用),并且可以利用应用程序中的 OSGi 层。考虑到您所说的混合捆绑包的类型,确实没有理由不这样做。

【讨论】:

我完全同意。我们正在使用 RCP 进行一些开发,并遇到了几乎相同的问题。最后,我们简单地捆绑了我们所有的库和一个简单的方式(取决于有多少项目需要它们),然后让我们的插件依赖它们。使用这种方法更容易管理,并且无头 PDE 构建效果很好。 我试过了,这种方法确实存在运行时问题【参考方案2】:

我从来没有这样做过,所以这是一种理论上的方法。但我会尝试像 ivy 或 maven2 这样的依赖管理系统。

由于 maven2 做的更多,所以只是依赖管理,在这种情况下我会推荐 ivy。

【讨论】:

在工作中习惯了 Maven 之后,我在家里将它用于我所有的项目,即使它们只是我个人使用的小玩具项目。依赖管理是美妙而不可或缺的。我没有亲自使用过 ivy,所以我无法直接与它交谈。【参考方案3】:

我们的解决方案使用 Ant 构建器将普通 Java 项目的“类”目录直接复制到插件项目的***目录中。我们跳过 JAR 构建步骤以节省时间,而且效果很好。如果插件项目依赖于已经构建的外部 JAR,我们也将它们复制进去。

这正是在 Eclipse 3.5 中设置它的方法(对于奇怪的格式,我很抱歉,但这是我能找到保留缩进的唯一方法):

Create empty "classes" dir in plugin project
Select plugin project, hit F5 to refresh resources
Create new Ant build file in plugin project to copy dependencies (ours is shown below)

Right-click plugin project, select Properties
  Select Builders
  Click "New..." (brings up Edit Configuration dialog)
    Select Ant Builder and click "OK"
    Name your builder (ours is called "PluginProject externals")
    Browse workspace for Buildfile (ours is $workspace_loc:/PluginProject/copyDependencies.xml)
    click Refresh tab
      check "Refresh resources upon completion", click "Specific resources"
      click "Specify Resources...", check box for the classes dir, click "Finish"
  Click "OK" (closes Edit Configuration dialog)
  Click "Up" to move "PluginProject externals" to top of builder list
Click "OK" (closes Properties dialog)

Open your plugin project's MANIFEST.MF
Click "Runtime" tab
Click "Add..." under "Classpath", select your the "classes" dir and JARs and click "OK"

在插件项目中手动创建空的“类”目录是为了让您可以告诉您的新构建器刷新该资源(在新构建器运行之前该资源尚不存在)。这是我们的 copyDependencies.xml 文件中的内容:

<project name="Copy dependencies" default="copyDependencies" basedir=".">
  <!--
    This copying is needed because it appears that Eclipse plugins can't
    depend directly on external Eclipse projects.
  -->
  <description>
    Copies external dependency class andd JAR files into this plugin's directory.
  </description>

  <target name="copyDependencies">
    <copy file="../External/JDOM/jdom-1.0/build/jdom.jar" todir="." preservelastmodified="true"/>
    <copy file="../External/Xalan/xalan-j_2_6_0/bin/xalan.jar" todir="." preservelastmodified="true"/>
    <copy file="../External/Xalan/xalan-j_2_6_0/bin/xercesImpl.jar" todir="." preservelastmodified="true"/>
    <copy file="../External/Xalan/xalan-j_2_6_0/bin/xml-apis.jar" todir="." preservelastmodified="true"/>
    <copy todir="./classes/com/arm" preservelastmodified="true">
      <fileset dir="../Utilities/src/com/arm" excludes="**/*.java"/>
    </copy>
  </target>
  <target name="clean" description="Deletes local copies of external classes and JARs.">
    <delete file="jdom.jar" quiet="true"/>
    <delete file="xalan.jar" quiet="true"/>
    <delete file="xercesImpl.jar" quiet="true"/>
    <delete file="xml-apis.jar" quiet="true"/>
    <delete dir="./classes/com/arm/utilities" quiet="true"/>
  </target>
</project>

此方法的唯一缺点似乎是 Eclipse 在需要调用外部构建器时并不是 100% 完美,因此有时您必须在 Eclipse 中执行“Project > Clean...”强迫它。

【讨论】:

【参考方案4】:

你有我的同情。我也曾与这个问题和 Eclipse 开发人员的沉默之墙在一个简单而明显的问题上作斗争:如何声明从插件到普通 Java 项目的依赖关系(使其在运行时工作)?

我认为他们不支持它。我解决这个问题的唯一方法是在我的插件项目中创建文件夹,这些文件夹实际上是指向 java 项目的 bin/ 文件夹的链接,然后将这些文件夹包含到插件中。这至少可行,但由于需要绝对文件系统路径,它很脆弱。

【讨论】:

他们实际上正在尝试改善现在的情况,并且正在开发一个全新的构建系统,该系统将 (afaik) 用更优雅的架构设计取代当前笨重的 PDE 构建,称为 b3我>。到目前为止,开发看起来很有希望,但目前仍处于初始实施阶段,因此对此发表任何明智的意见还为时过早...... 不幸的是,在 b3 构建系统上的积极工作在这一点上几乎停止了 不要使用文件系统链接,使用来自 @ctr0 的链接源选项。至少这可以让你使用像 WORKSPACE_LOC/something 这样的变量来避免绝对路径。 基本上,您不能让插件依赖于不是插件或插件提供的包的东西。这是插件运行时不支持它的问题,因为该运行时中的所有东西都应该是插件。【参考方案5】:

也许您可以在 Eclipse 上使用“项目属性”->“部署程序集”,并将其他项目添加到您的主项目中。其他项目看起来像“jar”,它们会自动添加到您的部署文件(war、ear 或其他)中。也许这可以工作。至少它对我有用。祝你好运!!

白羊座。

【讨论】:

这很好,但“部署组装”功能仅适用于 web/ear 项目,不适用于插件项目。【参考方案6】:

构建路径属性中有一个“链接源”选项,允许您为项目定义其他源文件夹。您可以选择另一个工作区项目的“src”文件夹并将其重命名为“src2”或您想要的任何名称。通过这种方式,类被编译并部署到插件项目输出文件夹中,并且可以在运行时加载。

【讨论】:

您愿意详细说明一下吗。当前形式的答案太简洁了,无法弄清楚您实际做了什么以及它如何或为什么有所帮助...... 两个项目,A 和 B。A 是我们的插件。 B 是一个常规的 Java 项目。您希望在构建 A 时包含来自 B 的代码。链接源选项可让您告诉项目 A:其他地方的文件夹包含源代码。我希望您像项目 A 中的其他源文件夹一样编译这些文件夹中的代码。有意义吗?【参考方案7】:

有了一组复杂的构建依赖项,我发现 Maven2 和 Hudson(用于 CI)是一个非常好的组合。我花了一些时间来设置基础架构并了解配置,但在那之后,它就开始工作了。

当然,您的构建机制依赖于 Maven2(或 Hudson)支持。我不确定 Eclipse Headless 构建的支持情况如何。但是,如果您使用 Eclipse headless 的唯一原因是允许在一个地方表达依赖关系,请帮自己一个忙并切换。

【讨论】:

我的问题不在于管理依赖关系,而在于按摩 Eclipse IDE 以了解这些(有些不兼容的)项目类型之间的依赖关系。我的目标是让整个工作区的行为与您仅开发具有项目到项目依赖关系的普通 Java 项目一样(例如,自动重建、代码完成提示和所有正常工作的东西)。【参考方案8】:

我遇到了完全相同的问题。我们有一组可以由 Maven 构建的多个普通 java 项目,并且应该(当前)都共享相同的类路径以正常工作。这些项目可用于在非 OSGi 环境中启动服务器。然后我们还有一个 Eclipse RCP 客户端,它将这些项目作为一个捆绑包使用。我完全能够使用 Apache Felix Maven Bundle Plugin 使用 Maven 构建这个大包,并且一切正常。但是每当我在正常项目中更改一个类时,我都必须重建整个包。增量构建和资源链接不起作用。

我尝试了“解决方案”,将这些项目中的二进制文件/源目录链接到一个大捆绑包的清单类路径中,它似乎可以工作,但这将是一个真正的维护噩梦,因为我什至必须链接一些个人文件。

具有讽刺意味的是,由于在客户端使用了 OSGi,我实际上正在考虑将我们带有 Maven 模块的漂亮的模块化结构折叠到仅一个插件项目的子包中。这是一个比开发极其缓慢的更好的选择。

我将首先研究的另一个更好的替代方案(根据 OSGi 人员的说法)是将我所有的 Maven 模块放入 OSGi 包中。但这可能是一个真正的 PITA,因为我依赖于类路径扫描和组合来自多个包(有时具有相同名称)的多个配置文件以形成一个配置。

(具体来说,我们使用 Spring 框架,我们将多个 persistence.xml 文件合并到一个持久性上下文中。我们还合并了来自不同模块的几个 Spring XML 上下文文件(都提供不同的 ASPECT),它们应该一起形成一个 Spring 上下文由 Spring-DM 使用。)

【讨论】:

是的,Spring 是在 OSGi 环境中使用的混蛋。休眠也是如此。如果适合我,我会完全放弃在 OSGi 中使用它们

以上是关于如何在 Eclipse PDE 中表达项目间依赖关系的主要内容,如果未能解决你的问题,请参考以下文章

如何在 GraphQL 中表达输入验证

我将如何在 Scala 中表达链式赋值?

如何在 Django 中表达一对多关系?

如何在 EF Core 和 LINQ 中表达 GetDate() 和 DateAdd() 方法?

如何在 Django 1.9 中表达 sqlite LEFT OUTER JOIN?

在 python 的 berkeley db 中表达多列?