Gradle 设置以处理具有相同代码库但依赖项不同的两种部署类型

Posted

技术标签:

【中文标题】Gradle 设置以处理具有相同代码库但依赖项不同的两种部署类型【英文标题】:Gradle setup to handle two deployment types with the same code base but different dependencies 【发布时间】:2020-01-17 10:57:44 【问题描述】:

我正在开发一个新的 Web 应用程序项目,该项目必须在分布式环境中运行,以及一个很好的旧“将所有内容放入 war 文件并在 tomcat 上运行”环境。 两个版本的代码完全相同,只有一个小的 if/else 子句来处理不同的调用类型。

但是,我现在正在为 gradle 设置而苦苦挣扎。我有两个服务,我们称之为“DAO”和“Connector”作为例子。 DAO 使用连接器从数据源中检索数据。 在分布式模式下,DAO 必须依赖于 Connector:api,因为 DAO 应该只知道所说的 API,因为实现在其他地方运行。 在捆绑模式下,DAO 必须依赖于 Connector:bundle,因为所有内容都必须进入一个单独的 war-file。

我们生成的所有 jars 都使用 maven-publish 插件发布在我们的内部 nexus 3 服务器上。我们目前使用的是 gradle 版本 4.10.3,DAO 项目是更大的多项目设置的一部分,由紧密耦合的模块组成,而连接器是供另一个应用程序使用的共享服务。

为了完成这些事情,我尝试了许多想法。他们中的大多数都是完全错误的,所以我不会在这里讨论它们。我现在最终得到的是一个多发布设置。

  publishing 
    publications 
      dist(MavenPublication) 
        alias false
        from components.java
        afterEvaluate 
          artifact apiJar
        
      
      bundle(MavenPublication) 
        alias true
        from components.java
        afterEvaluate 
          artifactId "$artifactId-bundle"
        
      
    
    repositories ...

此设置现在生成 2 组 pom 和 jar 文件。一个用于 connector-api.jar,一个用于 connector-bundle.jar

在 DAO 依赖设置中,我现在必须使用 if 块来决定设置什么依赖:

gradle.taskGraph.whenReady  graph ->
    if (graph.hasTask(generatePomFileForBundlePublication))
      dependencies 
        implementation "com.example:Connector-bundle:1.0.0"
      
    
    else 
      dependencies 
        implementation "com.example:Connector:1.0.0:api"
      
    
  

但是,这会导致我在开发时不再有可用的库。所以我改为无条件添加api依赖。

这确实有点用,但现在生成的 pom 文件内部总是有 api 依赖项,当我构建捆绑版本时,它同时具有两个依赖项。

完成了这么长的解释后,这是我的问题: 有没有更好的方法来代替这个......拼凑? 如果没有,我至少可以处理依赖重复问题吗?当我构建捆绑版本时,我不希望拥有 api 包。它充其量是冗余的,最坏的情况是它增加了更多的冗余依赖项。我不能像上面说的那样有条件地添加它,因为我失去了针对API进行开发的能力,并且我不想一直手动添加和删除它。

感谢任何帮助,因为我完全没有想法。

PS:别名的使用是为了处理maven-publish插件在多项目环境下使用multi-publishing的问题(见https://github.com/gradle/gradle/issues/1061)

【问题讨论】:

【参考方案1】:

好的,在摒弃了我所有的先入之见并创建了一个 gradle 原型之后,我找到了一个可行的解决方案。这就是我所做的:

首先我向 gradle.properties 添加了一个新属性mode=dist 这使我能够通过 if(mode == "dist")else 块拆分我的依赖项。例如:

dependencies 
  if (mode == "dist")
    implementation "com.example:Connector:1.0.0:api" 
   else 
    implementation "com.example:Connector-bundle:1.0.0"
  

由于这个设置,默认情况下 gradle 现在就像我处于分发模式一样,这意味着我总是加载 API 库,而不是完整的东西。

接下来我创建了一个自定义任务 publishBundle,在其中设置 mode = "lib" 并执行整个构建和发布过程。举个例子:

task publishBundle 
  mode = "lib"
  dependsOn "build"
  dependsOn "publishBundlePublicationToNexusRepository"

最后一次调整必须在发布配置中进行。在这里我也必须添加正确的模式值:

  publishing 
    publications 
      dist(MavenPublication) 
        mode = "dist"
        alias false
        from components.java
        afterEvaluate 
          artifact apiJar
        
      
      bundle(MavenPublication) 
        mode = "lib"
        alias true
        from components.java
        afterEvaluate 
          artifactId "$artifactId-bundle"
        
      
    
    repositories ...
  

这样,正常的构建和发布过程将遵循分布式方法,而 publishBundle 任务创建和发布包。在我们的存储库中,我们现在有两个连接器项目:connector 和 connector-bundle,这意味着我们可以根据我们所处的模式处理不同的依赖关系。

它仍然感觉像是拼凑而成,但我可以想象我的要求太……特别了。

【讨论】:

以上是关于Gradle 设置以处理具有相同代码库但依赖项不同的两种部署类型的主要内容,如果未能解决你的问题,请参考以下文章

C++ 两个库依赖于相同的库但不同的版本?

如何强制 Gradle 为两个依赖项设置相同的版本?

Gradle 无法构建具有 Docker 依赖项的 JAR

具有项目编译依赖项的 Gradle 嵌套多项目

如何使用 spring boot 插件 2.0.x 从一个具有不同依赖项的 gradle 项目生成 2 个 jars

如何根据构建变体使用 gradle 不同依赖模块的依赖项进行编译?