NamedDomainObjectContainer 的使用
2019-02-20 本文已影响0人
fan_xing
前提:对gradle的DSL对象创建有一定的了解
引言
gradle默认情况下对只包含原生数据类型的对象可以自动进行DSL匹配,如string、int、List等,通过project.extensions.create即可在extensions中创建该对象。当集合中(如List)包含自定义对象时,gradle提供了NamedDomainObjectContainer 来实现对象集合的DSL映射。
为了配合NamedDomainObjectContainer 的使用,
- 对象必须提供一个含有String的构造方法和一个name属性去唯一标识实例对象。
- 通过project.container去创建NamedDomainObjectContainer,
- 并由project.extensions.add来添加该NamedDomainObjectContainer实例。
快速上手
// File: build.gradle
apply plugin: ProductsPlugin
// DSL to define new objects of type Product.
products {
// Create Product with name pencil.
pencil {
price = 0.05
}
// Create Product with name crayon.
crayon {
price = 0.18
}
}
class ProductsPlugin implements Plugin<Project> {
void apply(final Project project) {
// Create NamedDomainObjectContainer instance for
// a collection of Product objects
NamedDomainObjectContainer<Product> productContainer =
project.container(Product)
// Add the container instance to our project
// with the name products.
project.extensions.add('products', productContainer)
// Simple task to show the Product objects
// that are created by Gradle using
// the DSL syntax in our build file.
project.task('reportProducts') << {
def products = project.extensions.getByName('products')
products.all {
// A Product instance is the delegate
// for this closure.
println "$name costs $price"
}
}
}
}
class Product {
// We need a name property
// so the object can be created
// by Gradle using a DSL.
String name
BigDecimal price
Product(final String name) {
this.name = name
}
}
运行结果
$ gradle -q reportProducts
crayon costs 0.18
pencil costs 0.05
$
进阶
嵌套情况下的使用
// File: build.gradle
apply plugin: com.mrhaki.gradle.DeploymentPlugin
deployments {
aws {
url = 'http://aws.address'
nodes {
node1 {
port = 9000
}
node2 {
port = 80
}
}
}
cf {
url = 'http://cf.address'
nodes {
test {
port = 10001
}
acceptanceTest {
port = 10002
}
}
}
}
Node类
// File: buildSrc/src/main/groovy/com/mrhaki/gradle/Node.groovy
package com.mrhaki.gradle
class Node {
String name
Integer port
/**
* We need this constructor so Gradle can create an instance
* from the DSL.
*/
Node(String name) {
this.name = name
}
}
Server类
// File: buildSrc/src/main/groovy/com/mrhaki/gradle/Server.groovy
package com.mrhaki.gradle
import org.gradle.api.NamedDomainObjectContainer
class Server {
/**
* An instance is created in the plugin class, because
* there we have access to the container() method
* of the Project object.
*/
NamedDomainObjectContainer<Node> nodes
String url
String name
/**
* We need this constructor so Gradle can create an instance
* from the DSL.
*/
Server(String name) {
this.name = name
}
/**
* Inside the DSL this method is invoked. We use
* the configure method of the NamedDomainObjectContainer to
* automatically create Node instances.
* Notice this is a method not a property assignment.
* <pre>
* server1 {
* url = 'http://server1'
* nodes { // This is the nodes() method we define here.
* port = 9000
* }
* }
* </pre>
*/
def nodes(final Closure configureClosure) {
nodes.configure(configureClosure)
}
}
我们需要这样定义插件
// File: buildSrc/src/main/groovy/com/mrhaki/gradle/DeploymentPlugin.groovy
package com.mrhaki.gradle
import org.gradle.api.Project
import org.gradle.api.Plugin
import org.gradle.api.NamedDomainObjectContainer
class DeploymentPlugin implements Plugin<Project> {
public static final String EXTENSION_NAME = 'deployments'
private static final String DEPLOY_TASK_PATTERN = 'deployOn%sTo%s'
private static final String REPORTING_TASK_NAME = 'reportDeployments'
private static final String TASK_GROUP_NAME = 'Deployment'
void apply(final Project project) {
setupExtension(project)
createDeploymentTasks(project)
createReportTask(project)
}
/**
* Create extension on the project for handling the deployments
* definition DSL with servers and nodes. This allows the following DSL
* in our build script:
* <pre>
* deployments {
* server1 {
* url = 'http://server'
* nodes {
* node1 {
* port = 9000
* }
* }
* }
* }
* </pre>
*/
private void setupExtension(final Project project) {
// Create NamedDomainObjectContainer for Server objects.
// We must use the container() method of the Project class
// to create an instance. New Server instances are
// automatically created, because we have String argument
// constructor that will get the name we use in the DSL.
final NamedDomainObjectContainer<Server> servers =
project.container(Server)
servers.all {
// Here we have access to the project object, so we
// can use the container() method to create a
// NamedDomainObjectContainer for Node objects.
nodes = project.container(Node)
}
// Use deployments as name in the build script to define
// servers and nodes.
project.extensions.add(EXTENSION_NAME, servers)
}
/**
* Create a new deployment task for each node.
*/
private void createDeploymentTasks(final Project project) {
def servers = project.extensions.getByName(EXTENSION_NAME)
servers.all {
// Actual Server instance is the delegate
// of this closure. We assign it to a variable
// so we can use it again inside the
// closure for nodes.all() method.
def serverInfo = delegate
nodes.all {
// Assign this closure's delegate to
// variable so we can use it in the task
// configuration closure.
def nodeInfo = delegate
// Make node and server names pretty
// for use in task name.
def taskName =
String.format(
DEPLOY_TASK_PATTERN,
name.capitalize(),
serverInfo.name.capitalize())
// Create new task for this node.
project.task(taskName, type: DeploymentTask) {
description = "Deploy to '${nodeInfo.name}' on '${serverInfo.name}'"
group = TASK_GROUP_NAME
server = serverInfo
node = nodeInfo
}
}
}
}
/**
* Add reporting task to project.
*/
private void createReportTask(final Project project) {
project.task(REPORTING_TASK_NAME, type: DeploymentReportTask) {
description = 'Show configuration of servers and nodes'
group = TASK_GROUP_NAME
}
}
}
DeploymentTask和DeploymentReportTask只是配合测试
// File: buildSrc/src/main/groovy/com/mrhaki/gradle/DeploymentTask.groovy
package com.mrhaki.gradle
import org.gradle.api.tasks.TaskAction
import org.gradle.api.DefaultTask
class DeploymentTask extends DefaultTask {
Server server
Node node
/**
* Simple implementation to show we can
* access the Server and Node instances created
* from the DSL.
*/
@TaskAction
void deploy() {
println "Deploying to ${server.url}:${node.port}"
}
}
// File: buildSrc/src/main/groovy/com/mrhaki/gradle/DeploymentReportTask.groovy
package com.mrhaki.gradle
import org.gradle.api.tasks.TaskAction
import org.gradle.api.DefaultTask
class DeploymentReportTask extends DefaultTask {
/**
* Simple task to show we can access the
* Server and Node instances also via the
* project extension.
*/
@TaskAction
void report() {
def servers = project.extensions.getByName(DeploymentPlugin.EXTENSION_NAME)
servers.all {
println "Server '${name}' with url '${url}':"
nodes.all {
println "\tNode '${name}' using port ${port}"
}
}
}
}
运行结果
$ gradle -q tasks
...
Deployment tasks
----------------
deployOnAcceptanceTestToCf - Deploy to 'acceptanceTest' on 'cf'
deployOnNode1ToAws - Deploy to 'node1' on 'aws'
deployOnNode2ToAws - Deploy to 'node2' on 'aws'
deployOnTestToCf - Deploy to 'test' on 'cf'
reportDeployments - Show configuration of servers and nodes
...
$ gradle -q deployOnNode2ToAws
Deploying to http://aws.address:80
$ gradle -q reportDeployments
Server 'aws' with url 'http://aws.address':
Node 'node1' using port 9000
Node 'node2' using port 80
Server 'cf' with url 'http://cf.address':
Node 'acceptanceTest' using port 10002
Node 'test' using port 10001
$
参见英文原版