Gradle 提供的属性对于惰性配置很重要。在实现自定义任务或插件时,务必使用这些惰性属性。
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 = 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
。
理解提供者
提供者是表示可能无法立即获得的值的对象。提供者对于惰性求值很有用,并且可以用于建模可能随时间变化或依赖于其他任务或输入的值
// 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() {
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 方法。
这是一个任务类型的示例,该任务类型具有类型为 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 方法声明只读管理属性,也称为提供者。该方法实现需要推导值。例如,它可以从其他属性推导值。
这是一个任务类型的示例,该任务类型具有从 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>
。
这是一个任务类型的示例,该任务类型具有 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 管理。这些类型的状态完全由 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);
}
}