Gradle 提供的屬性對於延遲組態非常重要。當實作自訂任務或外掛程式時,務必使用這些延遲屬性。

prop prov 1

Gradle 使用兩個介面表示延遲屬性

  1. Property - 表示可以查詢和更改的值。

  2. Provider - 表示只能查詢且無法更改的值。

屬性和供應器管理建置腳本中的值和組態

在此範例中,configuration 是一個 Property<String>,設定為 configurationProvider Provider<String>configurationProvider 延遲提供值 "Hello, Gradle!"

build.gradle.kts
abstract class MyIntroTask : DefaultTask() {
    @get:Input
    abstract val configuration: Property<String>

    @TaskAction
    fun printConfiguration() {
        println("Configuration value: ${configuration.get()}")
    }
}

val configurationProvider: Provider<String> = project.provider { "Hello, Gradle!" }

tasks.register("myIntroTask", MyIntroTask::class) {
    configuration.set(configurationProvider)
}
build.gradle
abstract class MyIntroTask extends DefaultTask {
    @Input
    abstract Property<String> getConfiguration()

    @TaskAction
    void printConfiguration() {
        println "Configuration value: ${configuration.get()}"
    }
}

Provider<String> configurationProvider = project.provider { "Hello, Gradle!" }

tasks.register("myIntroTask", MyIntroTask) {
    it.setConfiguration(configurationProvider)
}

了解屬性

Gradle 中的屬性是保存值的變數。它們可以在建置腳本中定義和存取,以儲存檔案路徑、版本號碼或自訂值等資訊。

可以使用 project 物件設定和檢索屬性

build.gradle.kts
// Setting a property
val simpleMessageProperty: Property<String> = project.objects.property(String::class)
simpleMessageProperty.set("Hello, World from a Property!")
// Accessing a property
println(simpleMessageProperty.get())
build.gradle
// Setting a property
def simpleMessageProperty = project.objects.property(String)
simpleMessageProperty.set("Hello, World from a Property!")
// Accessing a property
println(simpleMessageProperty.get())

屬性

  • 具有這些類型的屬性是可組態的。

  • Property 擴展了 Provider 介面。

  • Property.set(T) 方法為屬性指定一個值,覆寫可能存在的任何值。

  • Property.set(Provider) 方法為屬性的值指定一個 Provider,覆寫可能存在的任何值。這允許您在組態值之前將 ProviderProperty 實例連接在一起。

  • Property 可以通過 factory 方法 ObjectFactory.property(Class) 建立。

了解供應器

供應器是表示可能無法立即取得的值的物件。供應器適用於延遲評估,可用於建模可能隨時間變化或取決於其他任務或輸入的值

build.gradle.kts
// Setting a provider
val simpleMessageProvider: Provider<String> = project.providers.provider { "Hello, World from a Provider!" }
// Accessing a provider
println(simpleMessageProvider.get())
build.gradle
// Setting a provider
def simpleMessageProvider = project.providers.provider { "Hello, World from a Provider!" }
// Accessing a provider
println(simpleMessageProvider.get())

供應器

  • 具有這些類型的屬性是唯讀的。

  • Provider.get() 方法傳回屬性的當前值。

  • 可以使用 Provider.map(Transformer) 從另一個 Provider 建立 Provider

  • 許多其他類型擴展了 Provider,並且可以在需要 Provider 的任何地方使用。

使用 Gradle 管理的屬性

Gradle 的管理屬性允許您將屬性宣告為抽象 getter(Java、Groovy)或抽象屬性(Kotlin)。

然後 Gradle 會自動為這些屬性提供實作,管理它們的狀態。

屬性可以是可變的,表示它同時具有 get() 方法和 set() 方法

build.gradle.kts
abstract class MyPropertyTask : DefaultTask() {
    @get:Input
    abstract val messageProperty: Property<String> // message property

    @TaskAction
    fun printMessage() {
        println(messageProperty.get())
    }
}

tasks.register<MyPropertyTask>("myPropertyTask") {
    messageProperty.set("Hello, Gradle!")
}
build.gradle
abstract class MyPropertyTask extends DefaultTask {
    @Input
    abstract Property<String> messageProperty = project.objects.property(String)

    @TaskAction
    void printMessage() {
        println(messageProperty.get())
    }
}

tasks.register('myPropertyTask', MyPropertyTask) {
    messageProperty.set("Hello, Gradle!")
}

唯讀的,表示它僅具有 get() 方法。唯讀屬性是供應器

build.gradle.kts
abstract class MyProviderTask : DefaultTask() {
    final val messageProvider: Provider<String> = project.providers.provider { "Hello, Gradle!" } // message provider

    @TaskAction
    fun printMessage() {
        println(messageProvider.get())
    }
}

tasks.register<MyProviderTask>("MyProviderTask") {

}
build.gradle
abstract class MyProviderTask extends DefaultTask {
    final Provider<String> messageProvider = project.providers.provider { "Hello, Gradle!" }

    @TaskAction
    void printMessage() {
        println(messageProvider.get())
    }
}

tasks.register('MyProviderTask', MyProviderTask)

可變的管理屬性

可變的管理屬性是使用 Property<T> 類型的抽象 getter 方法宣告的,其中 T 可以是任何可序列化類型或完全管理的 Gradle 類型。屬性不得有任何 setter 方法。

以下是一個具有 URI 類型的 uri 屬性的任務類型範例

Download.java
public abstract class Download extends DefaultTask {
    @Input
    public abstract Property<URI> getUri(); // abstract getter of type Property<T>

    @TaskAction
    void run() {
        System.out.println("Downloading " + getUri().get()); // Use the `uri` property
    }
}

請注意,要使屬性被視為可變的管理屬性,屬性的 getter 方法必須是 abstract 並且具有 publicprotected 可見性。

屬性類型必須是以下之一

屬性類型 注意

Property<T>

其中 T 通常是 DoubleIntegerLongStringBool

RegularFileProperty

可組態的常規檔案位置,其值是可變的

DirectoryProperty

可組態的目錄位置,其值是可變的

ListProperty<T>

類型為 T 的元素列表

SetProperty<T>

類型為 T 的元素集合

MapProperty<K, V>

具有 V 類型值的 K 類型鍵的 Map

ConfigurableFileCollection

一個可變的 FileCollection,表示檔案系統位置的集合

ConfigurableFileTree

一個可變的 FileTree,表示檔案的層次結構

唯讀的管理屬性 (供應器)

您可以宣告唯讀的管理屬性,也稱為供應器,使用 Provider<T> 類型的 getter 方法。方法實作需要衍生值。例如,它可以從其他屬性衍生值。

以下是一個具有 uri 供應器的任務類型範例,該供應器從 location 屬性衍生而來

Download.java
public abstract class Download extends DefaultTask {
    @Input
    public abstract Property<String> getLocation();

    @Internal
    public Provider<URI> getUri() {
        return getLocation().map(l -> URI.create("https://" + l));
    }

    @TaskAction
    void run() {
        System.out.println("Downloading " + getUri().get());  // Use the `uri` provider (read-only property)
    }
}

唯讀的管理巢狀屬性 (巢狀供應器)

您可以通過為使用 @Nested 註釋的類型添加屬性的抽象 getter 方法來宣告唯讀的管理巢狀屬性。屬性不應具有任何 setter 方法。Gradle 為 getter 方法提供實作,並為屬性建立值。

當自訂類型具有具有相同生命週期的巢狀複雜類型時,此模式非常有用。如果生命週期不同,請考慮改用 Property<NestedType>

以下是一個具有 resource 屬性的任務類型範例。Resource 類型也是自訂 Gradle 類型,並定義了一些管理屬性

Download.java
public abstract class Download extends DefaultTask {
    @Nested
    public abstract Resource getResource(); // Use an abstract getter method annotated with @Nested

    @TaskAction
    void run() {
        // Use the `resource` property
        System.out.println("Downloading https://" + getResource().getHostName().get() + "/" + getResource().getPath().get());
    }
}

public interface Resource {
    @Input
    Property<String> getHostName();
    @Input
    Property<String> getPath();
}

唯讀的管理 "name" 屬性 (供應器)

如果類型包含一個名為 "name" 的 String 類型的抽象屬性,Gradle 將為 getter 方法提供實作,並使用一個 "name" 參數擴展每個建構子,該參數位於所有其他建構子參數之前。

如果類型是介面,Gradle 將提供一個帶有單個 "name" 參數和 @Inject 語意的建構子。

您可以讓您的類型實作或擴展 Named 介面,該介面定義了這樣一個唯讀的 "name" 屬性

import org.gradle.api.Named

interface MyType : Named {
    // Other properties and methods...
}

class MyTypeImpl(override val name: String) : MyType {
    // Implement other properties and methods...
}

// Usage
val instance = MyTypeImpl("myName")
println(instance.name) // Prints: myName

使用 Gradle 管理的類型

管理類型是抽象類別或介面,沒有欄位,並且其屬性都是管理的。這些類型的狀態完全由 Gradle 管理。

例如,此管理類型定義為介面

Resource.java
public interface Resource {
    @Input
    Property<String> getHostName();
    @Input
    Property<String> getPath();
}

具名管理類型是一種管理類型,此外還具有一個 String 類型的抽象屬性 "name"。具名管理類型特別適用於作為 NamedDomainObjectContainer 的元素類型

build.gradle.kts
interface MyNamedType {
    val name: String
}

class MyNamedTypeImpl(override val name: String) : MyNamedType

class MyPluginExtension(project: Project) {
    val myNamedContainer: NamedDomainObjectContainer<MyNamedType> =
        project.container(MyNamedType::class.java) { name ->
            project.objects.newInstance(MyNamedTypeImpl::class.java, name)
        }
}
build.gradle
interface MyNamedType {
    String getName()
}

class MyNamedTypeImpl implements MyNamedType {
    String name

    MyNamedTypeImpl(String name) {
        this.name = name
    }
}

class MyPluginExtension {
    NamedDomainObjectContainer<MyNamedType> myNamedContainer

    MyPluginExtension(Project project) {
        myNamedContainer = project.container(MyNamedType) { name ->
            new MyNamedTypeImpl(name)
        }
    }
}

使用 Java Bean 屬性

有時您可能會看到以 Java bean 屬性樣式實作的屬性。也就是說,它們不使用 Property<T>Provider<T> 類型,而是使用具體的 setter 和 getter 方法(或 Groovy 或 Kotlin 中的相應便利方法)實作。

這種屬性定義樣式在 Gradle 中是舊式的,不建議使用

public class MyTask extends DefaultTask {
    private String someProperty;

    public String getSomeProperty() {
        return someProperty;
    }

    public void setSomeProperty(String someProperty) {
        this.someProperty = someProperty;
    }

    @TaskAction
    public void myAction() {
        System.out.println("SomeProperty: " + someProperty);
    }
}