Gradle学习系列之一——Gradle快速入门

请通过以下方式下载本系列文章的Github示例代码:

git@github.com:kingmax-chan/gradle-learning.git

和Maven一样,Gradle只是提供了构建项目的一个框架,真正起作用的是Plugin。Gradle在默认情况下为我们提供了许多常用的Plugin,其中包括构建Java项目的Plugin,还有War,Ear等。与Maven不同的是,Gradle不提供内建的项目生命周期管理,只是Java Plugin向Project中添加了许多Task,这些Task依次执行,为我们营造了一种如同Maven般的项目构建周期。更多有关Maven的知识,读者可以访问Maven官网,或者可以参考笔者写的Maven学习系列文章。

  现在我们都在谈领域驱动设计,Gradle本身的领域对象主要有Project和Task。Project为Task提供了执行上下文,所有的Plugin要么向Project中添加用于配置的Property,要么向Project中添加不同的Task。一个Task表示一个逻辑上较为独立的执行过程,比如编译Java源代码,复制文件,打包Jar文件,甚至可以是执行一个系统命令或者调用Ant。另外,一个Task可以读取和设置Project的Property以完成特定的操作。
  让我们来看一个最简单的Task,创建一个build.gradle文件,内容如下:

task helloWorld << {
println "Hello World!"
}

注意:Gradle 5 不再支持 leftShift() 方法,所以<<必须去掉或者用doLast{}替代,不然会构建失败。
这里的“<<”表示向helloWorld中加入执行代码——其实就是groovy代码。Gradle向我们提供了一整套DSL(domain-specific language),所以在很多时候我们写的代码似乎已经脱离了groovy,但是在底层依然是执行的groovy。比如上面的task关键字,其实就是一个groovy中的方法,而大括号之间的内容则表示传递给task()方法的一个闭包。除了“<<”之外,我们还很多种方式可以定义一个Task,我们将在本系列后续的文章中讲到。

  在与build.gradle相同的目录下执行:

gradle helloWorld

命令行输出如下:

> Task :helloWorld
Hello World!
BUILD SUCCESSFUL in 1s
1 actionable task: 1 executed

在默认情况下,Gradle将当前目录下的build.gradle文件作为项目的构建文件。在上面的例子中,我们创建了一个名为helloWorld的Task,在执行gradle命令时,我们指定执行这个helloWorld Task。这里的helloWorld是一个DefaultTask类型的对象,这也是定义一个Task时的默认类型,当然我们也可以显式地声明Task的类型,甚至可以自定义一个Task类型(我们将在本系列的后续文章中讲到)。

  比如,我们可以定义一个用于文件复制的Task:

task copyFile(type: Copy) {
from 'xml'
into 'destination'
}

以上copyFile将xml文件夹中的所有内容复制到destination文件夹中。这里的两个文件夹都是相对于当前Project而言的,即build.gradle文件所在的目录。

  Task之间可以存在依赖关系,比如taskA依赖于taskB,那么在执行taskA时,Gradle会先执行taskB,然后再执行taskA。声明Task依赖关系的一种方式是在定义一个Task的时候:

task taskA(dependsOn: taskB) {
   //do something
}

Gradle在默认情况下为我们提供了几个常用的Task,比如查看Project的Properties、显示当前Project中定义的所有Task等。可以通过以下命令查看Project中所有的Task:

gradle tasks --all

输出如下:

> Task :tasks
------------------------------------------------------------
Tasks runnable from root project
------------------------------------------------------------
Build Setup tasks
-----------------
init - Initializes a new Gradle build.
wrapper - Generates Gradle wrapper files.
Help tasks
----------
buildEnvironment - Displays all buildscript dependencies declared in root project 'gradle-blog'.
components - Displays the components produced by root project 'gradle-blog'. [incubating]
dependencies - Displays all dependencies declared in root project 'gradle-blog'.
dependencyInsight - Displays the insight into a specific dependency in root project 'gradle-blog'.
dependentComponents - Displays the dependent components of components in root project 'gradle-blog'. [incubating]
help - Displays a help message.
model - Displays the configuration model of root project 'gradle-blog'. [incubating]
projects - Displays the sub-projects of root project 'gradle-blog'.
properties - Displays the properties of root project 'gradle-blog'.
tasks - Displays the tasks runnable from root project 'gradle-blog'.
Other tasks
-----------
copyFile
helloWorld
prepareKotlinBuildScriptModel
BUILD SUCCESSFUL in 1s
1 actionable task: 1 executed

可以看到,除了我们自己定义的copyFile和helloWorld之外,Gradle还默认为我们提供了dependencies、projects和properties等Task。dependencies用于显示Project的依赖信息,projects用于显示所有Project,包括根Project和子Project,而properties则用于显示一个Project所包含的所有Property。

  在默认情况下,Gradle已经为Project添加了很多Property,我们可以调用以下命令进行查看:

gradle properties

输出如下:

> Task :properties

* * *

## Root project

allprojects: [root project 'gradle-blog']
ant: org.gradle.api.internal.project.DefaultAntBuilder@7197350e
antBuilderFactory: org.gradle.api.internal.project.DefaultAntBuilderFactory@33b0aaff
artifacts: org.gradle.api.internal.artifacts.dsl.DefaultArtifactHandler_Decorated@34ec8bb6
asDynamicObject: DynamicObject for root project 'gradle-blog'
baseClassLoaderScope: org.gradle.api.internal.initialization.DefaultClassLoaderScope@479dbaf7
buildDir: E:\Git\gradle-blog\build
buildFile: E:\Git\gradle-blog\build.gradle
buildPath: :
buildScriptSource: org.gradle.groovy.scripts.TextResourceScriptSource@f6ac84f
buildscript: org.gradle.api.internal.initialization.DefaultScriptHandler@393b6c0f
childProjects: {}
class: class org.gradle.api.internal.project.DefaultProject_Decorated
classLoaderScope: org.gradle.api.internal.initialization.DefaultClassLoaderScope@69dae1a5
components: SoftwareComponentInternal set
configurationActions: org.gradle.configuration.project.DefaultProjectConfigurationActionContainer@433aa46b
configurationTargetIdentifier: org.gradle.configuration.ConfigurationTargetIdentifier![](https://www.nowcoder.com/equation?tex=1%401acb24f3%0Aconfigurations%3A%20configuration%20container%0Aconvention%3A%20org.gradle.api.internal.plugins.DefaultConvention%40787268b1%0AcopyFile%3A%20task%20'%3AcopyFile'%0AdefaultTasks%3A%20%5B%5D%0AdeferredProjectConfiguration%3A%20org.gradle.api.internal.project.DeferredProjectConfiguration%40461b69d3%0Adependencies%3A%20org.gradle.api.internal.artifacts.dsl.dependencies.DefaultDependencyHandler_Decorated%4050148487%0AdependencyLocking%3A%20org.gradle.internal.locking.DefaultDependencyLockingHandler_Decorated%4013bbdeca%0Adepth%3A%200%0Adescription%3A%20null%0AdisplayName%3A%20root%20project%20'gradle-blog'%0Aext%3A%20org.gradle.internal.extensibility.DefaultExtraPropertiesExtension%4078e70bec%0Aextensions%3A%20org.gradle.api.internal.plugins.DefaultConvention%40787268b1%0AfileOperations%3A%20org.gradle.api.internal.file.DefaultFileOperations%40652fa0d2%0AfileResolver%3A%20org.gradle.api.internal.file.BaseDirFileResolver%4011eb304c%0Agradle%3A%20build%20'gradle-blog'%0Agroup%3A%0AhelloWorld%3A%20task%20'%3AhelloWorld'%0AidentityPath%3A%20%3A%0AinheritedScope%3A%20org.gradle.internal.extensibility.ExtensibleDynamicObject&preview=true)InheritedDynamicObject@5c6bf135
layout: org.gradle.api.internal.file.DefaultProjectLayout@1c93393f
listenerBuildOperationDecorator: org.gradle.configuration.internal.DefaultListenerBuildOperationDecorator@422334f
logger: org.gradle.internal.logging.slf4j.OutputEventListenerBackedLogger@4c030ad7
logging: org.gradle.internal.logging.services.DefaultLoggingManager@4f62b83b
modelRegistry: org.gradle.model.internal.registry.DefaultModelRegistry@4a3d3a29
modelSchemaStore: org.gradle.model.internal.manage.schema.extract.DefaultModelSchemaStore@5f90d06a
module: org.gradle.api.internal.artifacts.ProjectBackedModule@2aa501c1
mutationState: project :
name: gradle-blog
normalization: org.gradle.normalization.internal.DefaultInputNormalizationHandler_Decorated@b912cfd
objects: org.gradle.api.internal.model.DefaultObjectFactory@51e8fed4
parent: null
parentIdentifier: null
path: :
pluginManager: org.gradle.api.internal.plugins.DefaultPluginManager_Decorated@72276ab2
plugins: [org.gradle.api.plugins.HelpTasksPlugin@2b6df71c, org.gradle.buildinit.plugins.BuildInitPlugin@2999c048, org.gradle.buildinit.plugins.WrapperPlugin@3f9185f1]
processOperations: org.gradle.process.internal.DefaultExecActionFactory![](https://www.nowcoder.com/equation?tex=DecoratingExecActionFactory%4076aa0a4b%0Aproject%3A%20root%20project%20'gradle-blog'%0AprojectConfigurator%3A%20org.gradle.api.internal.project.BuildOperationCrossProjectConfigurator%40323bc695%0AprojectDir%3A%20E%3A%5CGit%5Cgradle-blog%0AprojectEvaluationBroadcaster%3A%20ProjectEvaluationListener%20broadcast%0AprojectEvaluator%3A%20org.gradle.configuration.project.LifecycleProjectEvaluator%405547db1a%0AprojectPath%3A%20%3A%0AprojectRegistry%3A%20org.gradle.api.internal.project.DefaultProjectRegistry%40664a724e%0Aproperties%3A%20%7B...%7D%0Aproviders%3A%20org.gradle.api.internal.provider.DefaultProviderFactory%404094d49e%0Arepositories%3A%20repository%20container%0AresourceLoader%3A%20org.gradle.internal.resource.transfer.DefaultUriTextResourceLoader%402c77bd77%0Aresources%3A%20org.gradle.api.internal.resources.DefaultResourceHandler%4047033ce8%0ArootDir%3A%20E%3A%5CGit%5Cgradle-blog%0ArootProject%3A%20root%20project%20'gradle-blog'%0Ascript%3A%20false%0AscriptHandlerFactory%3A%20org.gradle.api.internal.initialization.DefaultScriptHandlerFactory%4072eeee44%0AscriptPluginFactory%3A%20org.gradle.configuration.ScriptPluginFactorySelector%401438f4a3%0AserviceRegistryFactory%3A%20org.gradle.internal.service.scopes.ProjectScopeServices&preview=true)4@5b57f56
services: ProjectScopeServices
standardOutputCapture: org.gradle.internal.logging.services.DefaultLoggingManager@4f62b83b
state: project state 'EXECUTED'
status: release
subprojects: []
tasks: task set
version: unspecified
BUILD SUCCESSFUL in 1s
1 actionable task: 1 executed

在以上Property中,allprojects表示所有的Project,这里只包含一个根Project,在多项目构建中,它将包含多个Project;buildDir表示构建结果的输出目录;我们自己定义的helloWorld和copyFile也成为了Project中的Property。另外,Project还包括用于执行Ant命令的DefaultAntBuilder(Property名为ant)和Project的描述属性description。
在下一篇文章中,我们将讲到创建Task的多种方法。

全部评论

相关推荐

2025-12-24 15:25
已编辑
门头沟学院 前端工程师
是腾讯的csig腾讯云,前天晚上九点突然打电话约面,激动的通宵学了一晚上,第二天状态很差改了今天(以后再也不通宵学习了)感觉自己浪费了面试官一个半小时单纯手写+场景,无八股无项目无算法,打击真的很大,全是在面试官提醒的情况下完成的,自己技术方面真的还是有待提高,实力匹配不上大厂和已经面试的两个公司完全不一样,很注重编码能力和解决问题的能力,然而我这两个方面都很薄弱,面试官人很好很耐心的等我写完题目,遇到瓶颈也会提醒我,写不出题也会很耐心的跟我讲解好感动,到最后面试结束还安慰我打算把下周最后一场面试面完之后就不面啦,如果能去实习还是很开心,但是最重要的还是好好努力提高技术以下是面经第一题//&nbsp;实现一个解析&nbsp;url&nbsp;参数的函数function&nbsp;parseUrl(urlStr)&nbsp;{//&nbsp;TODO}parseUrl('*********************************************');//&nbsp;返回&nbsp;{a:&nbsp;1,&nbsp;b:&nbsp;2,&nbsp;c:&nbsp;3}追问:在链接里见过什么部分?用&nbsp;hash&nbsp;路由的话放在哪第二题//&nbsp;考虑有一个异步任务要执行,返回&nbsp;Promise,这个任务可能会失败,请实现&nbsp;retry&nbsp;方法,返回新方法,可以在失败后自动重试指定的次数。/***&nbsp;异步任务重试*&nbsp;@param&nbsp;task&nbsp;要执行的异步任务*&nbsp;@param&nbsp;times&nbsp;需要重试的次数,默认为&nbsp;3&nbsp;次*/function&nbsp;retry(task,&nbsp;times&nbsp;=&nbsp;3)&nbsp;{//&nbsp;TODO:&nbsp;请实现}//&nbsp;---------------测试示例&nbsp;----------------//&nbsp;原方法const&nbsp;request&nbsp;=&nbsp;async&nbsp;(data)&nbsp;=&gt;&nbsp;{//&nbsp;模拟失败if&nbsp;(Math.random()&nbsp;&lt;&nbsp;0.7)&nbsp;{throw&nbsp;new&nbsp;Error('request&nbsp;failed');}const&nbsp;res&nbsp;=&nbsp;await&nbsp;fetch(&#39;https://jsonplaceholder.typicode.com/posts&#39;,&nbsp;{method:&nbsp;'POST',body:&nbsp;JSON.stringify(data),});return&nbsp;res.json();}//&nbsp;新的方法const&nbsp;requestWithRetry&nbsp;=&nbsp;retry(request);//&nbsp;使用async&nbsp;function&nbsp;run()&nbsp;{const&nbsp;res&nbsp;=&nbsp;await&nbsp;requestWithRetry({&nbsp;body:&nbsp;'content'&nbsp;});console.log(res);}run();第三题就是给&nbsp;retry&nbsp;函数添加类型注释,用到泛型第四题:在组件库中将&nbsp;Alert&nbsp;用&nbsp;api&nbsp;的形式实现(应该就是&nbsp;message&nbsp;这个组件)怎么渲染到一个浮层里而不是原地渲染出来
不知道怎么取名字_:技术这个东西,太杂了,而且要下功夫的
查看5道真题和解析
点赞 评论 收藏
分享
不愿透露姓名的神秘牛友
2025-12-17 16:48
今天九点半到公司,我跟往常一样先扫了眼电脑,屁活儿没有。寻思着没事干,就去蹲了个厕所,回来摸出手机刷了会儿。结果老板刚好路过,拍了我一下说上班别玩手机,我吓得赶紧揣兜里。也就过了四十分钟吧,我的直属领导把我叫到小隔间,上来就给我一句:“你玩手机这事儿把老板惹毛了,说白了,你可以重新找工作了,等下&nbsp;HR&nbsp;会来跟你谈。”&nbsp;我当时脑子直接宕机,一句话都没憋出来。后面&nbsp;HR&nbsp;找我谈话,直属领导也在旁边。HR&nbsp;说我这毛病不是一次两次了,属于屡教不改,不光上班玩手机,还用公司电脑看论文、弄学校的事儿。我当时人都傻了,上班摸鱼是不对,可我都是闲得发慌的时候才摸啊!而且玩手机这事儿,从来没人跟我说过后果这么严重,更没人告诉我在公司学个习也算犯错!连一次口头提醒都没有,哪儿来的屡教不改啊?更让我膈应的是,昨天部门刚开了会,说四个实习生里留一个转正,让大家好好表现。结果今天我就因为玩手机被开了。但搞笑的是,开会前直属领导就把我叫去小会议室,明明白白告诉我:“转正这事儿你就别想了,你的学历达不到我们部门要求,当初招你进来也没打算给你这个机会。”合着我没入贵厂的眼是吧?可我都已经被排除在转正名单外了,摸个鱼至于直接把我开了吗?真的太离谱了!
rush$0522:转正名单没进,大概率本来就没打算留你
摸鱼被leader发现了...
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务