java 如何解决 Gradle 中的循环依赖

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/38062841/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-03 03:04:43  来源:igfitidea点击:

How to resolve circular dependency in Gradle

javagradle

提问by ordonezalex

I am migrating a Java project from Ant to Gradle. I think the best solution is to use Gradle's multi-project support, but I cannot find a way to get rid of a circular dependency.

我正在将一个 Java 项目从 Ant 迁移到 Gradle。我认为最好的解决方案是使用 Gradle 的多项目支持,但我找不到摆脱循环依赖的方法。

The original project was setup to have this layout:

原始项目设置为具有以下布局:

- project/
  - common/
  - product-a/
  - product-b/

The relationship between common, product-a, and product-bis tricky. The commondepends on product-aor product-b, depending on a configuration file. Likewise, product-aand product-bdepend on common, regardless of the configuration property. product-aand product-bwill never be built at the same time.

commonproduct-a、 和之间的关系product-b很棘手。将common取决于product-aproduct-b根据配置文件。同样,product-a并且product-b依赖于common,无论配置属性如何。product-a并且product-b永远不会同时建造。

I thought a quick solution would be to use something like this in the project/build.gradle:

我认为一个快速的解决方案是在以下内容中使用类似的东西project/build.gradle

project(':product-a') {
    dependencies {
        compile project(':common')
    }
}

project(':product-b') {
    dependencies {
        compile project(':common')
    }
}

Next, I thought about getting a way to get this closer to working for just product-a. That led me to this:

接下来,我想到了一种方法来让这更接近于为product-a. 这让我想到了这个:

project(':common') {
    dependencies {
        compile project(':product-a')
    }
}

This will throw an exception for having a circular dependency.

这将引发循环依赖的异常。

I've considered refactoring product-aand product-bby setting up interfaces of the classes expected by commonand product-a/product-bor by using polymorphism, but before I move forward with either of those, is there a better way to accomplish this with Gradle? I'm not ready to get rid of this technical debt yet.

我已经考虑过重构product-aproduct-b通过commonproduct-a/product-b或使用多态来设置类的接口,但是在我继续使用其中任何一个之前,是否有更好的方法来使用 Gradle 完成此任务?我还没有准备好摆脱这种技术债务。

采纳答案by David M. Karr

Removing a circular dependency cannot be resolved with build trickery. You're going to have to refactor your modules so there is no longer a circular dependency. From your module names, and with no other information, I would think you would want to extract the part of "common" that depends on "product-*" and put it into a new module.

使用构建技巧无法解决删除循环依赖项。你将不得不重构你的模块,这样就不再有循环依赖了。在没有其他信息的情况下,从您的模块名称中,我认为您会想要提取依赖于“product-*”的“common”部分并将其放入一个新模块中。

回答by Jhon Doe

project(':project-a') {
    dependencies {
        compile project(':project-b')
    }
}

project(':project-b') {
    dependencies {
        //circular dependency to :project-a
        compile project(':project-a')
    }


   compileJava {
       doLast {
           // NOTE: project-a needs :project-b classes to be included
           // in :project-a jar file hence the copy, mostly done if we need to  
           // to support different version of the same library
           // compile each version on a separate project
          copy {
               from "$buildDir/classes/java/main"
               include '**/*.class'
               into project(':project-a').file('build/classes/java/main')

     }
   }

 }
}

product-a --> build.gradle

product-a --> build.gradle

/**
 * Do nothing during configuration stage by
 * registering a GradleBuild task
 * will be referenced in the task compileJava doLast{}
 */
tasks.register("copyProjectBClasses", GradleBuild) {
  //we'll invoke this later
  def taskList = new ArrayList<String>()
  taskList.add(":product-b:compileJava")
  logger.lifecycle "Task to execute $taskList..."
  setTasks(taskList)
}

// make sure :project-b classes are compiled first and copied to this project before 
// all classes are added to the jar, so we do it after :project-a compiled.
compileJava {
  doLast {
    synchronized(this) {
      // create temp file to avoid circular dependency
      def newFile = new File("$buildDir/ongoingcopy.tmp")
      if (!newFile.exists()) {
        newFile.createNewFile()
        GradleBuild buildCopyProjectBClasses = tasks.getByName("copyProjectBClasses")
        buildCopyProjectBClasses.build()
      }
      newFile.delete()
    }
  }
}