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

Java 如何解决Gradle中的循环依赖,java,gradle,Java,Gradle,我正在将一个Java项目从Ant迁移到Gradle。我认为最好的解决方案是使用Gradle的多项目支持,但我无法找到摆脱循环依赖的方法 原始项目已设置为具有以下布局: - project/ - common/ - product-a/ - product-b/ common、product-a和product-b之间的关系很微妙。通用取决于产品-a或产品-b,具体取决于配置文件。同样地,product-a和product-b依赖于common,而与配置属性无关产品-a和产品-b永远

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

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

- project/
  - common/
  - product-a/
  - product-b/
common
product-a
product-b
之间的关系很微妙。通用
取决于
产品-a
产品-b
,具体取决于配置文件。同样地,
product-a
product-b
依赖于
common
,而与配置属性无关<代码>产品-a
产品-b
永远不会同时生成

我认为一个快速的解决方案是在
项目/build.gradle
中使用类似的东西:

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

project(':product-b') {
    dependencies {
        compile project(':common')
    }
}
接下来,我想找到一种方法,让它更接近于只为
product-a
工作。这让我想到:

project(':common') {
    dependencies {
        compile project(':product-a')
    }
}
这将引发具有循环依赖项的异常


我曾考虑过通过设置
common
product-a
所期望的类的接口来重构
product-a
/
product-b
或使用多态性,但在我进一步研究这两种方法之前,有没有更好的方法通过Gradle来实现这一点?我还没有准备好摆脱这种技术债务。

删除循环依赖项不能用构建技巧解决。您将不得不重构模块,这样就不再存在循环依赖关系。在没有其他信息的情况下,我认为您应该从模块名称中提取依赖于“product-*”的“common”部分,并将其放入新模块中

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

/**
 * 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()
    }
  }
}
/**
*在配置阶段不执行任何操作
*注册GradleBuild任务
*将在任务compileJava doLast{}中引用
*/
任务。注册(“copyProjectBClasses”,GradleBuild){
//我们稍后将调用此函数
def taskList=new ArrayList()
任务列表。添加(“:product-b:compileJava”)
logger.lifecycle“要执行的任务$taskList…”
设置任务(任务列表)
}
//确保:先编译project-b类,然后再复制到此项目
//所有类都被添加到jar中,所以我们在:project-a compiled之后进行。
内贾瓦{
多拉斯特{
已同步(此){
//创建临时文件以避免循环依赖
def newFile=新文件($buildDir/ongoingcopy.tmp)
如果(!newFile.exists()){
newFile.createNewFile()
gradlebuildCopyProjectBClasses=tasks.getByName(“copyProjectBClasses”)
buildCopyProjectBClasses.build()
}
newFile.delete()
}
}
}

我在这里描述了消除循环的重构过程: