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` 实例连接起来。
-
一个 `Property` 可以通过工厂方法 ObjectFactory.property(Class) 创建。
理解提供者
提供者是表示可能无法立即获得的值的对象。提供者对于延迟评估很有用,可以用于建模可能随时间变化或依赖于其他任务或输入的值。
// 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` 可以使用 Provider.map(Transformer) 从另一个 `Provider` 创建。
-
许多其他类型扩展了 `Provider`,可以在需要 `Provider` 的任何地方使用。
使用 Gradle 托管属性
Gradle 的托管属性允许你将属性声明为 getter(Java、Groovy)或属性(Kotlin)。
Gradle 然后自动为这些属性提供实现,管理它们的状态。
一个属性可以是_可变的_,这意味着它是 `Property` 类型,它同时具有 `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> getMessageProperty()
@TaskAction
void printMessage() {
println(messageProperty.get())
}
}
tasks.register('myPropertyTask', MyPropertyTask) {
messageProperty.set("Hello, Gradle!")
}
或者_只读_,这意味着它是 `Provider` 类型,它只有 `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 方法必须具有 `public` 或 `protected` 可见性。建议也将该属性设为 `abstract`,以便 Gradle 可以管理该属性的初始化。
属性类型必须是以下之一
属性类型 | 注意 |
---|---|
|
其中 `T` 通常是 `Double`、`Integer`、`Long`、`String` 或 `Bool` |
|
可配置的常规文件位置,其值是可变的 |
|
可配置的目录位置,其值是可变的 |
|
类型为 `T` 的元素列表 |
|
类型为 `T` 的元素集合 |
|
键类型为 `K`,值类型为 `V` 的 Map |
|
一个可变的 `FileCollection`,表示文件系统位置的集合 |
|
一个可变的 `FileTree`,表示文件层次结构 |
只读托管属性 (Providers)
你可以使用 `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”的 `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);
}
}