属性“mainClass”是最终的,不能再更改

问题描述 投票:0回答:5

我最近为 Spring Boot 项目将 Gradle 从 4.x 升级到了 6.6。我以为我终于把它全部启动并运行了,但后来意识到我们的一个应用程序可能启动两个类型为

BootRun
(例如 A 和 B)的不同配置任务,但无法启动第二个 B 实例。

这是我尝试运行第二个实例时的错误:

Build file 'C:\Users\...\build.gradle' line: 17

Execution failed for task ':apps:myapp:bootRunB'.
> The value for task ':apps:myapp:bootRunB' property 'mainClass' is final and cannot be changed any further.

这是我的

build.gradle
文件中配置任务的部分:

task bootRunB(type: org.springframework.boot.gradle.tasks.run.BootRun, dependsOn: 'build') {
    group = 'Application'

    doFirst() {
        main = bootJar.mainClassName
        classpath = bootRun.classpath
        systemProperty '...'
    }
}

如有任何建议,我们将不胜感激。

gradle build.gradle
5个回答
9
投票

Gradle 最近引入了一个用于“惰性配置”的 API,现在插件扩展和任务类型等内部功能已迁移到这个新 API。总之,可以说,构建脚本中的(几乎)每个配置属性都应该使用 Property<T>

Provider<T>
(只读)来实现,而不仅仅是简单类型的 getter 和 setter 
T
。为了提供向后兼容性,许多属性没有更改,但添加了新属性,并且旧属性读取和写入这些新属性。
您的问题也是如此,因为 Spring Boot Gradle 插件中的任务类型 

BootRun

 扩展了 Gradle 提供的 
JavaExec
 任务类型。添加了新属性 
mainClass
(a
Property<string>
),并修改了旧属性
main
以使用新属性。方法
getMain()
使用
mainClass
Property.get()
读取,方法
setMain(String)
(在 Groovy 中使用语法
main = '...'
时调用)使用
mainClass
写入
Property.set(String)
这一切都可以正常工作,但是 Gradle 为其惰性配置 API 引入了一些附加功能。这些功能之一是可写属性的最终确定(

Property<>

)。在构建过程中的某个时刻,将出于其原始目的(运行任务)读取任务属性(例如

mainClass
),因此该点之后的任何更改都不会生效。在 Gradle 的早期版本中,这会导致很多难以调试的问题,因为 Gradle 不会显示任何错误。现在,一旦出于最初目的而读取这些属性,它们就会被最终确定,从而导致当有人随后尝试更改它们时 Gradle 会失败。
关于您的用例,属性

mainClass

(由

main
访问)已在
doFirst
闭包中最终确定,因此您需要提前应用此配置。由于您想要将该值设置为属性
bootJar.mainClassName
的值(这是一个简单的
String
),因此您必须确保该属性在读取用于配置
bootRunB
任务之前具有其最终值:
bootJar {
    mainClassName = '...'
}

task bootRunB(type: org.springframework.boot.gradle.tasks.run.BootRun, dependsOn: 'build') {
    group = 'Application'

    main = bootJar.mainClassName
    // From this point, bootRun.classpath must not be changed !
    classpath = bootRun.classpath
    systemProperty '...'
}

要消除对配置顺序的依赖,您可以使用 

Provider<String>

: 创建一个 
Project.provider(...)
task bootRunB(type: org.springframework.boot.gradle.tasks.run.BootRun, dependsOn: 'build') { group = 'Application' main = provider({ bootJar.mainClassName }) classpath = bootRun.classpath systemProperty '...' }



2
投票

task bootRunB(type: org.springframework.boot.gradle.tasks.run.BootRun, dependsOn: 'build') { group = 'Application' mainClass = 'com.App' doFirst() { main = bootJar.mainClassName classpath = bootRun.classpath systemProperty '...' } }



2
投票
缩短线路命令

。 请看下面的截图

注意:在我的情况下

用户本地默认值:无

正在工作


0
投票

它现在提供了一个需要提供者的新属性。 不要填写 main 属性,而是填写 mainClass 属性:

kts脚本语言示例:

tasks.register<BootRun>("myBootRunTask") { dependsOn("assemble") group = "Application" val bootJarTask = tasks.getByName<BootJar>("bootJar") mainClass.set(provider { bootJarTask.mainClassName }) classpath = bootJarTask.classpath ... }



0
投票
© www.soinside.com 2019 - 2024. All rights reserved.