【问题标题】:Gradle and Spring-bootRun can not find my classGradle 和 Spring-bootRun 找不到我的班级
【发布时间】:2020-09-24 13:11:50
【问题描述】:

有两个项目:

  • 经典(有主课)
  • 高级

我希望高级版拥有Classic 拥有的所有课程。但是当我运行Advanced/gradle bootRun 时,所有Advanced 类似乎都不见了。

高级/src/main/java/foo/Bar.java:

package foo;
public class Bar{
   //empty
}

Classic/src/main/java/foo/Classic.java:

package foo;
public class Classic {
  public static void main(){
    try {
        Class.forName("foo.Bar");
    } catch (ClassNotFoundException e) {
        e.printStackTrace();
    }
  }
}

例外:

java.lang.ClassNotFoundException: foo.Bar
    at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:602)
    at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:178)
    at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:522)
    at java.base/java.lang.Class.forName0(Native Method)
    at java.base/java.lang.Class.forName(Class.java:340)
    at foo.Classic.main(Classic.java:14)
java.lang.ClassNotFoundException: foo.Bar
    at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:602)
    at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:178)
    at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:522)
    at org.springframework.boot.devtools.restart.classloader.RestartClassLoader.loadClass(RestartClassLoader.java:144)
    at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:522)
    at java.base/java.lang.Class.forName0(Native Method)
    at java.base/java.lang.Class.forName(Class.java:340)
    at foo.Classic.main(Classic.java:14)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:564)
    at org.springframework.boot.devtools.restart.RestartLauncher.run(RestartLauncher.java:49)

我的 Advanced/build.gradle 中有这个:

...
dependencies{
  ...
  implementation project(':classic')
  ...
}
...

来自评论的重要信息:

Jacob G. 我在其中一个聊天室和 OP 聊了一会儿,发现了一些事情。尝试使用 Gradle 构建 Advanced 项目时,它会报告 50+ 个关于 package not found: 的编译错误,指的是 Classic 项目中的包。此外,Classic 和 Advanced 不共享根项目,所以我觉得尝试依赖 project(':classic') 是徒劳的。 OP 声明只能对 Advanced 进行提交,因此可能根本无法解决该问题。对于任何好奇的人,OP 也没有使用 IDE。

尊重声明

我对问题进行了编辑,添加了限制。这是一个非常重要的编辑,我只能在 Advanced 中提交更改。由于我没有 gradle 经验,我不知道这些附加信息的重要性。为迟到感到抱歉,为礼貌感到安慰,希望理解。

【问题讨论】:

  • 您正在尝试在经典模块中加载高级模块类 foo.Bar。根据 gradle config Classic 模块不依赖于 Advanced 模块它是相反的方式。
  • 你能分享一个最小的可重现 git 吗?
  • @Grim 在那之前,我认为结构/模块的照片很有帮助。是在谈论一个具有多模块(Advance/Classic)的项目还是两个独立的项目?
  • 我的意思是你的项目结构是什么,它们是多模块项目中的两个模块(共享父 gradle.build)还是独立的(没有相关的 gradle.build?)
  • @Grim 如果不是项目结构,我希望您分享您的 gradle 文件,以便我们可以识别您的孩子和父母的关系。

标签: java spring-boot gradle dependencies


【解决方案1】:

据我所知,我们正在处理一个多项目场景。在这种情况下,multi project builds documentation 告诉我们必须在包含两个项目的文件夹中有一个 settings.gradle:

那么可以在没有cd更改目录到特定文件夹的情况下运行两个项目,但可以直接从多项目根目录通过命令:gradle advanced:bootRun

根据20200610 EDIT of the question 进行编辑,确认规范:只能对Advanced 项目进行提交

我们仍然可以获得解决方案,但在这种情况下(实际上不是 gradle 多项目)

  • 不需要在Advanced的父目录级别有settings.gradle;它满足不能在Advanced之外提交的要求

  • Classic 项目的构建方式无关紧要,我们不关心它,因为我们无法提交它

  • 我们不能在 Advanced/build.gradle 中使用 implementation project(':classic') 作为依赖项,因为这仅适用于 真正的 gradle 多项目场景;在这里,我们必须使用文件依赖项或另一个可用于用户开发环境的type of dependecy

在这种情况下,可以通过cd Advanced 运行高级项目,然后从 Advanced 目录运行命令:gradle bootRun

为什么有效?

..为了更好地理解它是如何工作的,让我们检查一下 SystemClassLoader的当前路径通过在Advanced/src/main/java/com/example/springboot/Application.java中添加这行代码

ClassLoader cl = ClassLoader.getSystemClassLoader();
URL[] urls = ((URLClassLoader)cl).getURLs();
for(URL url: urls){
    System.out.println(url.getFile());
}

输出是:

<multi-project-root>/Advanced/build/classes/java/main/
<multi-project-root>/Advanced/build/resources/main/
<multi-project-root>/Classic/build/libs/Classic-0.0.1-SNAPSHOT.jar
~/.gradle/caches/modules-2/files-2.1/org.springframework.boot/spring
... [suppressed many othe spring devtools and gradle related caches  ]

这允许高级和经典类找到彼此

概念证明的源代码

POC source-code new branch 已相应更新

【讨论】:

  • 我希望我正确解释了这个案例,我的图片来源是github.com/rondinif/gradle-multi-project-poc,如果有一些误解或澄清,可以更改或分叉以适应不同的场景
  • 是的,但 settings.gradle 并不一定与 Advanced 和 Classic 处于同一目录级别,因为我只承诺 Advanced-Directory 的内容。
  • @Grim github.com/rondinif/gradle-multi-project-poc/tree/… 是一个新分支,通过从Advanced 文件夹启动gradle bootRun 来工作;由于修改了问题,我也更新了答案
  • ? 我从未见过这样的订婚。我会等待分支成功。 :)
  • ? 对于使用 POC 操作的任何问题,或者您想要澄清或要求更改其中包含的代码,您可以直接从以下链接打开问题:github.com/rondinif/gradle-multi-project-poc/issues/new
【解决方案2】:

你需要的是 Gradle 的composite build。见我的POC project。 进阶项目包括this line的经典项目

advanced/App.java 调用classic.App.main,而the classic.App class 可以从advanced 项目中加载foo.Bar。无需对经典项目进行提交。

在高级文件夹中执行“gradlew run”

看看它是如何工作的。

【讨论】:

  • +1 :我之前没有考虑过。我认为这个解决方案非常适合用例。我也试过in my POC repo,我确认它就像一个魅力。
【解决方案3】:

我的项目结构也与您的项目结构相同,因此通过进行以下提到的更改,它对我来说效果很好:

  1. build.gradle 文件中的条目

编译项目(':Classic')

  1. settings.gradle 中的条目
include ':Classic'
project(':Classic').projectDir = new File(settingsDir, '../../libs/Classic')

我希望这对您也有用,是的,在进行这些更改后不要忘记重建您的成绩项目。

【讨论】:

  • 这确实使用gradle bootRun 编译。不幸的是,Classic 中仍未找到该类。
猜你喜欢
  • 2014-06-18
  • 2018-01-08
  • 1970-01-01
  • 2013-05-26
  • 2017-05-27
  • 2016-06-01
相关资源
最近更新 更多