Gradle 提供了对于延迟配置很重要的属性。当实现自定义 task 或插件时,必须使用这些延迟属性。

Gradle 使用两个接口表示延迟属性
属性和提供者管理构建脚本中的值和配置。
在这个例子中,configuration
是一个 Property<String>
,它被设置为 configurationProvider
Provider<String>
。configurationProvider
延迟地提供值 "Hello, Gradle!"
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)
}
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
对象设置和检索属性
// 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())
// 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
,覆盖可能存在的任何值。这允许您在配置值之前将Provider
和Property
实例连接在一起。 -
可以通过工厂方法 ObjectFactory.property(Class) 创建
Property
。
理解提供者
提供者是表示可能不会立即可用的值的对象。提供者对于延迟求值非常有用,并且可以用于建模可能随时间变化或依赖于其他 task 或输入的值
// Setting a provider
val simpleMessageProvider: Provider<String> = project.providers.provider { "Hello, World from a Provider!" }
// Accessing a provider
println(simpleMessageProvider.get())
// 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()
方法
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!")
}
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()
方法。只读属性是提供者
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") {
}
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 方法。
这是一个 task 类型的示例,它具有 uri
属性,类型为 URI
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
并且具有 public
或 protected
可见性。
属性类型必须是以下之一
属性类型 | 注意 |
---|---|
|
其中 |
|
可配置的常规文件位置,其值是可变的 |
|
可配置的目录位置,其值是可变的 |
|
类型为 |
|
类型为 |
|
具有 |
|
一个可变的 |
|
一个可变的 |
只读的管理属性(提供者)
您可以声明只读的管理属性,也称为提供者,使用类型为 Provider<T>
的 getter 方法。方法实现需要派生值。例如,它可以从其他属性派生值。
这是一个 task 类型的示例,它具有从 location
属性派生的 uri
提供者
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>
代替。
这是一个 task 类型的示例,它具有 resource
属性。Resource
类型也是自定义 Gradle 类型,并定义了一些管理属性
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 管理。
例如,此管理类型被定义为一个接口
public interface Resource {
@Input
Property<String> getHostName();
@Input
Property<String> getPath();
}
命名管理类型是一种管理类型,它还额外具有一个名为 "name" 的类型为 String
的抽象属性。命名管理类型作为 NamedDomainObjectContainer 的元素类型特别有用
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)
}
}
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);
}
}