如何在Gradle中解决循环依赖

时间:2016-06-27 20:39:42

标签: java gradle

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

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

String imageURL = new String("https://graph.facebook.com/" + accessToken.getUserId() + "/picture?type=small");
loadBitmap(imageURL);

globalMap.setOnMapLongClickListener(
    // ...
    // the same code without imageURL initialization and bitmap loading
);

- project/ - common/ - product-a/ - product-b/ commonproduct-a之间的关系很棘手。 product-b取决于commonproduct-a,具体取决于配置文件。同样,product-bproduct-a依赖于product-b,无论配置属性如何。 commonproduct-a永远不会同时建立。

我认为快速解决方案是在product-b

中使用类似的内容
project/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') } } product-a / product-b所期望的类的接口或使用多态来重构commonproduct-a,但在我向前推进其中任何一个之前,有没有更好的方法来实现Gradle?我还没准备好摆脱这种技术债务。

2 个答案:

答案 0 :(得分:7)

使用构建技巧无法解决删除循环依赖关系。您将不得不重构您的模块,因此不再存在循环依赖。从你的模块名称,没有其他信息,我认为你会想要提取" common"这取决于"产品 - *"并将其放入一个新的模块中。

答案 1 :(得分:0)

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()
    }
  }
}