Gradle 和 Spring-bootRun 找不到我的 class

Gradle and Spring-bootRun can not find my class

有两个项目:

我想让 Advanced 拥有 Classic 的所有 classes。但正如我 运行 Advanced/gradle bootRun 所有 Advanced classes 似乎都丢失了。

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 多个关于找不到包的编译错误:,指的是 Classic 项目中的包。此外,Classic 和 Advanced 不共享根项目,所以我觉得尝试依赖 project(':classic') 是徒劳的。 OP 声明只能提交到 Advanced,因此可能根本无法解决该问题。对于任何好奇的人,OP 也没有使用 IDE.

尊重声明

我对问题进行了编辑,添加了一个限制。这是一个非常重要的编辑,我只能在 Advanced 中提交更改。因为我没有 gradle 方面的经验,所以我没有意识到这些附加信息的重要性。晚限深表歉意,礼遇倍感欣慰,望谅解

我也有和你一样的项目结构,所以通过进行下面提到的更改它对我来说效果很好:

  1. build.gradle 文件中的条目

compile project(':Classic')

  1. 进入 settings.gradle
include ':Classic'
project(':Classic').projectDir = new File(settingsDir, '../../libs/Classic')

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

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

然后可以 运行 两个项目都没有 cd 将目录更改到特定文件夹,但直接从多项目根目录通过命令:gradle advanced:bootRun

根据 20200610 编辑问题 确认规范:只能对 Advanced 项目 提交.

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

  • 不需要在Advanced的父目录级别有settings.gradle;它满足无法在 Advanced

  • 之外提交的要求
  • Classic项目是如何构建的并不重要,我们不关心它,因为我们不能提交它

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

在这种情况下,可以通过 cd Advanced 然后从 Advanced 目录 运行 th 命令来 运行 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已相应更新

你需要的是Gradle的composite build. See my POC project。 高级项目包括this line

的经典项目

advanced/App.java调用classic.App.main, And the classic.App class可以从高级项目加载foo.Bar。无需提交经典项目。

在高级文件夹中执行"gradlew run"

看看它是如何工作的。