18. Gradle编译其他应用代码流程(六) - 执行Task过程
接上一篇17. Gradle编译其他应用代码流程(五) - 设置Task过程,这篇帖子讲task的执行过程。
以gradle pmd为例
一. 入口
文件路径:
subprojects\core\src\main\java\org\gradle\initialization\DefaultGradleLauncher.java
//ExecutebuildbuildOperationExecutor.run("Runtasks",newRunnable(){@Overridepublicvoidrun(){buildExecuter.execute(gradle);}});
subprojects\core\src\main\java\org\gradle\execution\DefaultBuildExecuter.java
publicclassDefaultBuildExecuterimplementsBuildExecuter{...publicvoidexecute(GradleInternalgradle){execute(gradle,0);}privatevoidexecute(finalGradleInternalgradle,finalintindex){if(index>=executionActions.size()){return;}BuildExecutionActionaction=executionActions.get(index);System.out.println("DefaultBuildExecuter.action:"+action+"index:"+index);action.execute(newBuildExecutionContext(){publicGradleInternalgetGradle(){returngradle;}publicvoidproceed(){execute(gradle,index+1);}});}}
DefaultBuildExecuter采用的方法和上一篇帖子一样,使用递归的方法处理executionActions这个集合(估计是同一个人写 ^_^)。
executionActions包含两个action
org.gradle.execution.DryRunBuildExecutionAction@1e4d93f7index:0org.gradle.execution.SelectedTaskExecutionAction@76673edindex:1
其实这两个action也是继承自同一接口
publicclassDryRunBuildExecutionActionimplementsBuildExecutionAction{}publicclassSelectedTaskExecutionActionimplementsBuildExecutionAction{}
下面来看每个action的执行流程:
DryRunBuildExecutionAction跳过所有的task
文件路径:
subprojects\core\src\main\java\org\gradle\execution\DryRunBuildExecutionAction.java
/***A{@linkorg.gradle.execution.BuildExecutionAction}thatdisablesallselectedtasksbeforetheyareexecuted.*/publicclassDryRunBuildExecutionActionimplementsBuildExecutionAction{publicvoidexecute(BuildExecutionContextcontext){GradleInternalgradle=context.getGradle();if(gradle.getStartParameter().isDryRun()){for(Tasktask:gradle.getTaskGraph().getAllTasks()){task.setEnabled(false);}}context.proceed();}}
从代码可以看到,它把所有的task都变成了enable=false;那这个是什么意思?
就是不执行任何task!
大家可以加上 --dry-run参数试试,比如gradle assemble --dry-run 这样就会跳过task执行过程,其他流程,比如配置,plugin等等都会执行。
这种情况对于一些不需要执行task的场景,可以加快执行速度。
:pushsdk:transformNative_libsWithSyncJniLibsForDebugSKIPPED:pushsdk:bundleDebugSKIPPED:pushsdk:compileDebugSourcesSKIPPED:pushsdk:assembleDebugSKIPPED:pushsdk:compileReleaseSourcesSKIPPED:pushsdk:assembleReleaseSKIPPED:pushsdk:assembleSKIPPED
2.SelectedTaskExecutionAction
文件路径:
subprojects\core\src\main\java\org\gradle\execution\SelectedTaskExecutionAction.java
publicclassSelectedTaskExecutionActionimplementsBuildExecutionAction{publicvoidexecute(BuildExecutionContextcontext){...taskGraph.addTaskExecutionGraphListener(newBindAllReferencesOfProjectsToExecuteListener());taskGraph.execute();}...}
文件路径:
subprojects\core\src\main\java\org\gradle\execution\taskgraph\DefaultTaskGraphExecuter.java
publicclassDefaultTaskGraphExecuterimplementsTaskGraphExecuter{...publicvoidexecute(){...taskPlanExecutor.process(taskExecutionPlan,newEventFiringTaskWorker(taskExecuter.create(),buildOperationExecutor.getCurrentOperationId()));...}}
文件路径:
subprojects\core\src\main\java\org\gradle\execution\taskgraph\DefaultTaskPlanExecutor.java
classDefaultTaskPlanExecutorextendsAbstractTaskPlanExecutor{...@Overridepublicvoidprocess(TaskExecutionPlantaskExecutionPlan,Action<?superTaskInternal>taskWorker){System.out.println("DefaultTaskPlanExecutorcurrentthread:"+Thread.currentThread());taskWorker(taskExecutionPlan,taskWorker,buildOperationWorkerRegistry).run();taskExecutionPlan.awaitCompletion();}}
文件路径:
subprojects\core\src\main\java\org\gradle\execution\taskgraph\AbstractTaskPlanExecutor.java
privatestaticclassTaskExecutorWorkerimplementsRunnable{...publicvoidrun(){...while((task=taskExecutionPlan.getTaskToExecute())!=null){BuildOperationWorkerRegistry.Completioncompletion=buildOperationWorkerRegistry.operationStart();try{...processTask(task);...}finally{completion.operationFinish();}}...}protectedvoidprocessTask(TaskInfotaskInfo){...taskWorker.execute(taskInfo.getTask());...}}
文件路径:
subprojects\core\src\main\java\org\gradle\execution\taskgraph\DefaultTaskGraphExecuter.java
/***Thisactionwillsetthestartandendtimesontheinternaltaskstate,andwillmakesure*thatwhenataskisstarted,thepubliclistenersareexecutedaftertheinternallisteners*areexecutedandwhenataskisfinished,thepubliclistenersareexecutedbeforetheinternal*listenersareexecuted.Basicallytheinternallistenersembracethepubliclisteners.*/privateclassEventFiringTaskWorkerimplementsAction<TaskInternal>{...@Overridepublicvoidexecute(TaskInternaltask){...try{taskListeners.getSource().beforeExecute(task);System.out.println("EventFiringTaskWorkertaskExecuter:"+taskExecuter+"task.getState():"+task.getState());taskExecuter.execute(task,task.getState(),newDefaultTaskExecutionContext());taskListeners.getSource().afterExecute(task,state);}finally{longendTime=timeProvider.getCurrentTime();internalTaskListeners.getSource().afterExecute(taskOperation,newOperationResult(startTime,endTime,task.getState().getFailure()));}}}}
上面几段代码都是一直调用下来,并没有影响到主流程。
下面来看taskExecuter.execute(task, task.getState(), new DefaultTaskExecutionContext());
这个taskExecuter使用了装饰者模式,装饰者模式在gradle中使用的太多了(这句话好像不是第一次说了 ^_^)。
下面是包装的代码。
文件路径:
subprojects\core\src\main\java\org\gradle\internal\service\scopes\TaskExecutionServices.java
returnnewExecuteAtMostOnceTaskExecuter(newSkipOnlyIfTaskExecuter(newSkipTaskWithNoActionsExecuter(newSkipEmptySourceFilesTaskExecuter(taskInputsListener,newValidatingTaskExecuter(newSkipUpToDateTaskExecuter(repository,createSkipCachedExecuterIfNecessary(startParameter,gradle.getTaskCaching(),packer,newPostExecutionAnalysisTaskExecuter(newExecuteActionsTaskExecuter(listenerManager.getBroadcaster(TaskActionListener.class))))))))));
最后会调用到ExecuteActionsTaskExecuter里面。
不过我们可以稍微解释下各个封装Executer的作用。
ExecuteAtMostOnceTaskExecuter:检查是否已经执行过
SkipOnlyIfTaskExecuter:检查是否是skip(这个估计是个属性配置,暂时还没有找到在哪里配)
SkipTaskWithNoActionsExecuter:检查是否有action,没有则返回
SkipEmptySourceFilesTaskExecuter:检查是否有source file
这种设计模式的话,可以让每个类专注于自己的功能,然后像一根链条一样把他们串起来,从外到内,依次执行。同时外层还可以处理内层的返回结果。
3. ExecuteActionsTaskExecuter
这个executer从名字上面看就可以知道它的大概意思:执行actions,按照先后顺序,逐个执行action,如果某个action出错,那么将终止执行。
在gradle里面,有几个概念比较重要,从大到小: project,task, actions
一个project可以有多个子project; 一个project可以有多个task,task用来描述具体的操作;同时一个task可以包含多个action。
文件路径:
subprojects\core\src\main\java\org\gradle\api\internal\tasks\execution\ExecuteActionsTaskExecuter.java
/***A{@linkorg.gradle.api.internal.tasks.TaskExecuter}whichexecutestheactionsofatask.*/publicclassExecuteActionsTaskExecuterimplementsTaskExecuter{...publicvoidexecute(TaskInternaltask,TaskStateInternalstate,TaskExecutionContextcontext){...GradleExceptionfailure=executeActions(task,state,context);...}privateGradleExceptionexecuteActions(TaskInternaltask,TaskStateInternalstate,TaskExecutionContextcontext){...for(ContextAwareTaskActionaction:actions){state.setDidWork(true);task.getStandardOutputCapture().start();executeAction(task,action,context);...}returnnull;}privatevoidexecuteAction(TaskInternaltask,ContextAwareTaskActionaction,TaskExecutionContextcontext){action.contextualise(context);try{action.execute(task);}finally{action.contextualise(null);}}}
关于task的描述,大家可以看下Task.java的注释:
ATaskrepresentsasingleatomicpieceofworkforabuild,suchascompilingclassesorgeneratingjavadoc.EachtaskbelongstoaProject.Youcanusethevariousmethodsonorg.gradle.api.tasks.TaskContainertocreateandlookuptaskinstances.Forexample,org.gradle.api.tasks.TaskContainer.create(String)createsanemptytaskwiththegivenname.Youcanalsousethetaskkeywordinyourbuildfile:taskmyTasktaskmyTask{configureclosure}taskmyType<<{taskaction}taskmyTask(type:SomeType)taskmyTask(type:SomeType){configureclosure}Eachtaskhasaname,whichcanbeusedtorefertothetaskwithinitsowningproject,andafullyqualifiedpath,whichisuniqueacrossalltasksinallprojects.Thepathistheconcatenationoftheowningproject'spathandthetask'sname.Pathelementsareseparatedusingthe{@valueorg.gradle.api.Project#PATH_SEPARATOR}character.TaskActionsATaskismadeupofasequenceofActionobjects.Whenthetaskisexecuted,eachoftheactionsisexecutedinturn,bycallingAction.execute.YoucanaddactionstoataskbycallingdoFirst(Action)ordoLast(Action).Groovyclosurescanalsobeusedtoprovideataskaction.Whentheactionisexecuted,theclosureiscalledwiththetaskasparameter.YoucanaddactionclosurestoataskbycallingdoFirst(groovy.lang.Closure)ordoLast(groovy.lang.Closure)orusingtheleft-shift<<operator.Thereare2specialexceptionswhichataskactioncanthrowtoabortexecutionandcontinuewithoutfailingthebuild.Ataskactioncanabortexecutionoftheactionandcontinuetothenextactionofthetaskbythrowingaorg.gradle.api.tasks.StopActionException.Ataskactioncanabortexecutionofthetaskandcontinuetothenexttaskbythrowingaorg.gradle.api.tasks.StopExecutionException.Usingtheseexceptionsallowsyoutohavepreconditionactionswhichskipexecutionofthetask,orpartofthetask,ifnottrue.TaskDependenciesandTaskOrderingAtaskmayhavedependenciesonothertasksormightbescheduledtoalwaysrunafteranothertask.Gradleensuresthatalltaskdependenciesandorderingrulesarehonoredwhenexecutingtasks,sothatthetaskisexecutedafterallofitsdependenciesandany"mustrunafter"taskshavebeenexecuted.DependenciestoataskarecontrolledusingdependsOn(Object)orsetDependsOn(Iterable),andmustRunAfter(Object),setMustRunAfter(Iterable),shouldRunAfter(Object)andsetShouldRunAfter(Iterable)areusedtospecifyorderingbetweentasks.Youcanuseobjectsofanyofthefollowingtypestospecifydependenciesandordering:AString,CharSequenceorgroovy.lang.GStringtaskpathorname.Arelativepathisinterpretedrelativetothetask'sProject.Thisallowsyoutorefertotasksinotherprojects.ATask.Aclosure.TheclosuremaytakeaTaskasparameter.Itmayreturnanyofthetypeslistedhere.Itsreturnvalueisrecursivelyconvertedtotasks.Anullreturnvalueistreatedasanemptycollection.ATaskDependencyobject.ABuildableobject.AIterable,Collection,Maporarray.Maycontainanyofthetypeslistedhere.Theelementsoftheiterable/collection/map/arrayarerecursivelyconvertedtotasks.ACallable.Thecall()methodmayreturnanyofthetypeslistedhere.Itsreturnvalueisrecursivelyconvertedtotasks.Anullreturnvalueistreatedasanemptycollection.UsingaTaskinaBuildFileDynamicPropertiesATaskhas4'scopes'forproperties.Youcanaccessthesepropertiesbynamefromthebuildfileorbycallingtheproperty(String)method.YoucanchangethevalueofthesepropertiesbycallingthesetProperty(String,Object)method.TheTaskobjectitself.ThisincludesanypropertygettersandsettersdeclaredbytheTaskimplementationclass.Thepropertiesofthisscopearereadableorwritablebasedonthepresenceofthecorrespondinggetterandsettermethods.Theextensionsaddedtothetaskbyplugins.Eachextensionisavailableasaread-onlypropertywiththesamenameastheextension.Theconventionpropertiesaddedtothetaskbyplugins.Aplugincanaddpropertiesandmethodstoataskthroughthetask'sConventionobject.Thepropertiesofthisscopemaybereadableorwritable,dependingontheconventionobjects.Theextrapropertiesofthetask.Eachtaskobjectmaintainsamapofadditionalproperties.Thesearearbitraryname->valuepairswhichyoucanusetodynamicallyaddpropertiestoataskobject.Oncedefined,thepropertiesofthisscopearereadableandwritable.DynamicMethodsAPluginmayaddmethodstoaTaskusingitsConventionobject.ParallelExecutionBydefault,tasksarenotexecutedinparallel.Parallelexecutioncanbeenabledbythe--parallelflagwhenthebuildisinitiated.Inparallelmode,thetasksofdifferentprojects(i.e.inamultiprojectbuild)areabletobeexecutedinparallel.Ifataskisannotatedwithorg.gradle.api.tasks.ParallelizableTask,itmayalsobeexecutedinparallelwithothertasksofthesameproject.Seeorg.gradle.api.tasks.ParallelizableTaskformoredetailsonwritingparallelizabletasks.
个人理解意思是(仅供参考):
Task
一个task是一个独立的原子任务,比如编译一个类或者生成javadoc。
每个task都属于一个project,你可以使用TaskContainer里面的多个方法去创建或者查找task引用,例如:TaskContainer.create(String) 可以使用你传入的名字创建一个空的task。你也可以在你的build文件里面使用'task'关键字创建task。
taskmyTasktaskmyTask{configureclosure}taskmyType<<{taskaction}taskmyTask(type:SomeType)taskmyTask(type:SomeType){configureclosure}
每个task都有一个名字,这个名字可以用来和它所在的project关联,and a fully qualified path, which is unique across all tasks in all projects. The path is the concatenation of the owning project's path and the task's name. Path elements are separated using the {@value org.gradle.api.Project#PATH_SEPARATOR} character.(这段不是很理解,应该是完全限定路径)。
Task Actions
每个task都有一系列有顺序的action,当一个task被执行的时候,它的action会按照顺序被逐一执行。你可以通过doFirst(Action)或者doLast(Action)来添加action。
Groovy闭包当然也可以用来提供action,当action被执行的时候,闭包会被作为参数调用。你可以通过doFirst(groovy.lang.Closure)和doLast(groovy.lang.Closure)或者通过左偏移符号"<<"来添加闭包action。
这里有两个特殊的异常可以允许你去中断execution,但是不会让编译失败。
org.gradle.api.tasks.StopActionException可以中断当前执行的action,继续执行下一个action。
org.gradle.api.tasks.StopExecutionException可以中断当前task,继续执行下一个task。
通过这些异常控制,你可以进行一些预处理检查等等。
其实这两个异常通过代码也可以看出来。
for(ContextAwareTaskActionaction:actions){state.setDidWork(true);task.getStandardOutputCapture().start();try{executeAction(task,action,context);}catch(StopActionExceptione){//IgnoreLOGGER.debug("Actionstoppedbysomeactionwithmessage:{}",e.getMessage());}catch(StopExecutionExceptione){LOGGER.info("Executionstoppedbysomeactionwithmessage:{}",e.getMessage());break;}catch(Throwablet){returnnewTaskExecutionException(task,t);}finally{task.getStandardOutputCapture().stop();}}
Task Dependencies and Task Ordering
一个task可能会依赖于其他task,或者需要在其他task之后运行,gradle支持了这种功能。
依赖一个task可以使用dependsOn(Object)或者setDependsOn(Iterable)和mustRunAfter(Object), setMustRunAfter(Iterable), shouldRunAfter(Object) and setShouldRunAfter(Iterable) ,你可以使用上面这些方法指定先后关系。
在Build文件中使用Task
动态属性
task有4种范围的属性,你可以通过property(String)获取这个属性值,或者通过setProperty(String, Object)来设置值。
task本身
extensions
convention
extra
动态方法
plugin可能会通过Convention对象添加方法
并发执行
默认task是顺序执行的,并发执行可以通过--parallel 参数开启。
下一篇会讲讲gradle的守护进程编译。
声明:本站所有文章资源内容,如无特殊说明或标注,均为采集网络资源。如若本站内容侵犯了原著者的合法权益,可联系本站删除。