您好,登錄后才能下訂單哦!
繼續上一篇 13. Gradle編譯其他應用代碼流程(二)。
這篇從InProcessBuildActionExecuter.execute開始這一篇的內容。
在正式內容前,首先要講個gradle構建的流程,這個也是接下來內容的流程。
Load->Configure->Build
大家可以思考下,這3步都主要做了什么事。
另外,從執行流程的事件通知來看,它還分成下面5個通知事件:
buildStarted //開始編譯 settingsEvaluated //settings處理完畢 projectsLoaded //項目loaded projectsEvaluated //項目處理完畢 buildFinished //編譯結束
一. InProcessBuildActionExecuter.execute
文件路徑: subprojects\launcher\src\main\java\org\gradle\launcher\exec\InProcessBuildActionExecuter.java 方法: public Object execute(BuildAction action, BuildRequestContext buildRequestContext, BuildActionParameters actionParameters, ServiceRegistry contextServices) { GradleLauncher gradleLauncher = gradleLauncherFactory.newInstance(action.getStartParameter(), buildRequestContext, contextServices); try { gradleLauncher.addStandardOutputListener(buildRequestContext.getOutputListener()); gradleLauncher.addStandardErrorListener(buildRequestContext.getErrorListener()); GradleBuildController buildController = new GradleBuildController(gradleLauncher); buildActionRunner.run(action, buildController); System.out.println("Sandy buildController.getResult(): " + buildController.getResult()); return buildController.getResult(); } finally { gradleLauncher.stop(); } } 文件路徑: subprojects\launcher\src\main\java\org\gradle\launcher\exec\InProcessBuildActionExecuter.java 方法: public GradleInternal run() { try { System.out.println("Sandy GradleInternal run state: " + state); return (GradleInternal) getLauncher().run().getGradle(); } finally { state = State.Completed; } } 文件路徑: subprojects\launcher\src\main\java\org\gradle\launcher\exec\ChainingBuildActionRunner.java 方法: @Override public void run(BuildAction action, BuildController buildController) { System.out.println("Sandy ChainingBuildActionRunner run runners.size: " + runners.size()); for (BuildActionRunner runner : runners) { System.out.println("runner: " + runner); runner.run(action, buildController); if (buildController.hasResult()) { return; } } throw new UnsupportedOperationException(String.format("Don't know how to run a build action of type %s.", action.getClass().getSimpleName())); } 文件路徑: subprojects\launcher\src\main\java\org\gradle\tooling\internal\provider\ExecuteBuildActionRunner.java 方法: public void run(BuildAction action, BuildController buildController) { System.out.println("ExecuteBuildActionRunner action: " + action + " buildController: " + buildController); if (action instanceof ExecuteBuildAction) { System.out.println("ExecuteBuildActionRunner run.."); buildController.run(); buildController.setResult(null); System.out.println("ExecuteBuildActionRunner result: " + "null"); } } 文件路徑: subprojects\launcher\src\main\java\org\gradle\launcher\exec\GradleBuildController.java 方法: public GradleInternal run() { try { System.out.println("Sandy GradleInternal run state: " + state); return (GradleInternal) getLauncher().run().getGradle(); } finally { state = State.Completed; } }
上面的步驟比較清晰明了,需要注意的是ChainingBuildActionRunner和ExecuteBuildActionRunner,其實他們都是同一個接口BuildActionRunner,所以這里又是喜聞樂見的裝飾者模式。
public class ChainingBuildActionRunner implements BuildActionRunner { private final List<? extends BuildActionRunner> runners; public ChainingBuildActionRunner(List<? extends BuildActionRunner> runners) { this.runners = runners; } } public class ExecuteBuildActionRunner implements BuildActionRunner {}
最后來到ExecuteBuildActionRunner.run方法,它會調用GradleBuildController.run(),顧名思義,它是GradleBuild的控制器,所以馬上就要接觸到Gradle build步驟了;接下來會調用DefaultGradleLauncher.run()方法。
二. DefaultGradleLauncher
@Override public BuildResult run() { return doBuild(Stage.Build); } private BuildResult doBuild(final Stage upTo) { return buildOperationExecutor.run("Run build", new Factory<BuildResult>() { @Override public BuildResult create() { Throwable failure = null; try { System.out.println("buildListener: " + buildListener.getClass() + " gradle: " + gradle.getClass()); buildListener.buildStarted(gradle); doBuildStages(upTo); } catch (Throwable t) { failure = exceptionAnalyser.transform(t); } BuildResult buildResult = new BuildResult(upTo.name(), gradle, failure); buildListener.buildFinished(buildResult); if (failure != null) { throw new ReportedException(failure); } return buildResult; } }); }
首先來看buildListener.buildStarted(gradle); 這行代碼的作用是通知gradle構建已經開始,那既然是通知,接收者是誰呢?
看buildListener賦值的地方:
文件路徑:
subprojects\core\src\main\java\org\gradle\initialization\DefaultGradleLauncher.java
方法
public DefaultGradleLauncher(GradleInternal gradle, InitScriptHandler initScriptHandler, SettingsLoader settingsLoader, BuildConfigurer buildConfigurer, ExceptionAnalyser exceptionAnalyser, LoggingManagerInternal loggingManager, BuildListener buildListener, ModelConfigurationListener modelConfigurationListener, BuildCompletionListener buildCompletionListener, BuildOperationExecutor operationExecutor, BuildConfigurationActionExecuter buildConfigurationActionExecuter, BuildExecuter buildExecuter, BuildScopeServices buildServices) { ... this.buildListener = buildListener; ... }
繼續看調動的地方
文件路徑:
subprojects\core\src\main\java\org\gradle\initialization\DefaultGradleLauncherFactory.java
方法:
return new DefaultGradleLauncher( ... gradle.getBuildListenerBroadcaster(), ... );
//文件路徑:
subprojects\core\src\main\java\org\gradle\invocation\DefaultGradle.java
public BuildListener getBuildListenerBroadcaster() { return buildListenerBroadcast.getSource(); } public DefaultGradle(Gradle parent, StartParameter startParameter, ServiceRegistryFactory parentRegistry) { ... buildListenerBroadcast = getListenerManager().createAnonymousBroadcaster(BuildListener.class); projectEvaluationListenerBroadcast = getListenerManager().createAnonymousBroadcaster(ProjectEvaluationListener.class); buildListenerBroadcast.add(new BuildAdapter() { @Override public void buildStarted(Gradle gradle) { super.buildStarted(gradle); Exception ex = new Exception("Sandy buildStarted"); ex.printStackTrace(); System.out.println("buildListenerBroadcast sandy buildStarted"); } @Override public void settingsEvaluated(Settings settings) { super.settingsEvaluated(settings); Exception ex = new Exception("Sandy settingsEvaluated"); ex.printStackTrace(); System.out.println("buildListenerBroadcast sandy settingsEvaluated"); } @Override public void projectsEvaluated(Gradle gradle) { super.projectsEvaluated(gradle); System.out.println("buildListenerBroadcast sandy projectsEvaluated"); } @Override public void buildFinished(BuildResult result) { super.buildFinished(result); System.out.println("buildListenerBroadcast sandy buildFinished"); } @Override public void projectsLoaded(Gradle gradle) { System.out.println("buildListenerBroadcast sandy projectsLoaded"); rootProjectActions.execute(rootProject); rootProjectActions = null; } }); }
嗯,也就是接受者是在DefaultGradle里面,也就是說通知gradle build已經開始,接下來看doBuildStages(Stage.Build)方法,這個方法很重要,gradle build的主要流程都在這里面。
private void doBuildStages(Stage upTo) { if (stage == Stage.Build) { throw new IllegalStateException("Cannot build with GradleLauncher multiple times"); } if (stage == null) { // Evaluate init scripts initScriptHandler.executeScripts(gradle); // Build `buildSrc`, load settings.gradle, and construct composite (if appropriate) settings = settingsLoader.findAndLoadSettings(gradle); stage = Stage.Load; } if (upTo == Stage.Load) { return; } if (stage == Stage.Load) { // Configure build buildOperationExecutor.run("Configure build", new Runnable() { @Override public void run() { buildConfigurer.configure(gradle); if (!gradle.getStartParameter().isConfigureOnDemand()) { buildListener.projectsEvaluated(gradle); } modelConfigurationListener.onConfigure(gradle); } }); stage = Stage.Configure; } if (upTo == Stage.Configure) { return; } // After this point, the GradleLauncher cannot be reused stage = Stage.Build; // Populate task graph buildOperationExecutor.run("Calculate task graph", new Runnable() { @Override public void run() { buildConfigurationActionExecuter.select(gradle); if (gradle.getStartParameter().isConfigureOnDemand()) { buildListener.projectsEvaluated(gradle); } } }); // Execute build buildOperationExecutor.run("Run tasks", new Runnable() { @Override public void run() { buildExecuter.execute(gradle); } }); }
還記得最開始說過的gradle構建分成3個步驟嗎?Load-> Configure->Build
那這個方法doBuildStages可以很清楚的看到這個流程,大家看下上面的代碼即可明白,那接下來我們一步步分析這個過程。
三. Load.executeScripts 初始化腳本
if (stage == null) { // Evaluate init scripts initScriptHandler.executeScripts(gradle); // Build `buildSrc`, load settings.gradle, and construct composite (if appropriate) settings = settingsLoader.findAndLoadSettings(gradle); stage = Stage.Load; }
1. 首先來看第一行
initScriptHandler.executeScripts(gradle);
// Evaluate init scripts 看解釋是統計初始化腳本,那具體是干什么呢?
文件路徑:
subprojects\core\src\main\java\org\gradle\initialization\InitScriptHandler.java
/** * Finds and executes all init scripts for a given build. */ public class InitScriptHandler { ... public void executeScripts(final GradleInternal gradle) { System.out.println("executeScripts"); final List<File> initScripts = gradle.getStartParameter().getAllInitScripts(); if (initScripts.isEmpty()) { return; } BuildOperationDetails operationDetails = BuildOperationDetails.displayName("Run init scripts").progressDisplayName("init scripts").build(); buildOperationExecutor.run(operationDetails, new Runnable() { @Override public void run() { for (File script : initScripts) { System.out.println("InitScriptHandler run processor" + processor); processor.process(new UriScriptSource("initialization script", script), gradle); } } }); } }
從類InitScriptHandler的注釋就知道,這個類的作用是找到并且執行初始化腳本,那我們接下來看看:
a. 它說的初始化腳本指的是什么?
b. 怎么執行初始化腳本的?
2. 首先來看getAllInitScripts是在干什么:
subprojects\core\src\main\java\org\gradle\StartParameter.java
public List<File> getAllInitScripts() { CompositeInitScriptFinder initScriptFinder = new CompositeInitScriptFinder( new UserHomeInitScriptFinder(getGradleUserHomeDir()), new DistributionInitScriptFinder(gradleHomeDir) ); List<File> scripts = new ArrayList<File>(getInitScripts()); initScriptFinder.findScripts(scripts); return Collections.unmodifiableList(scripts); }
subprojects\core\src\main\java\org\gradle\initialization\UserHomeInitScriptFinder.java
public void findScripts(Collection<File> scripts) { File userInitScript = new File(userHomeDir, "init.gradle"); if (userInitScript.isFile()) { scripts.add(userInitScript); } findScriptsInDir(new File(userHomeDir, "init.d"), scripts); }
subprojects\core\src\main\java\org\gradle\initialization\DistributionInitScriptFinder.java
public void findScripts(Collection<File> scripts) { if (gradleHome == null) { return; } findScriptsInDir(new File(gradleHome, "init.d"), scripts); }
3個作用:
a. 嘗試找到環境變量'GRADLE_USER_HOME'目錄下的init.gradle文件,并加入列表。
如果沒有配置環境變量'GRADLE_USER_HOME',那么目錄就是'C:\Users\xxx(你的用戶名)\.gradle'
b. 找到環境變量'GRADLE_USER_HOME'下面init.d目錄下的 *.gradle配置文件,并加入列表。
c. 找到gradle home目錄下init.d目錄的 *.gradle配置文件,并加入列表。
我的gradle_user_home和gradle_home分別是:
gradleUserHomeDir=D:\gradle_jar_cache gradleHome=E:\work_space\gradle-source-from-csdn\gradle-3.1\build\distributions\gradle-3.1-snapshot-1
其實如果大家去看下gradle home目錄的init.d目錄,你會發現里面有個readme.txt文件,里面有這樣的描述:
You can add .gradle init scripts to this directory. Each one is executed at the start of the build.
那我們的Gradle 源代碼流程分析也驗證了這句話。
3. 然后來看看processor.process在干什么
for (File script : initScripts) { processor.process(new UriScriptSource("initialization script", script), gradle); }
首先initScripts是指上面我們統計3個目錄下得到的腳本文件集合,那這里就是挨個執行它們。
那UriScriptSource是用來解析傳入的script文件,把它的內容讀出來。
那繼續看process方法
文件路徑:
subprojects\core\src\main\java\org\gradle\configuration\DefaultInitScriptProcessor.java
/** * Processes (and runs) an init script for a specified build. Handles defining * the classpath based on the initscript {} configuration closure. */ public class DefaultInitScriptProcessor implements InitScriptProcessor { ... public void process(final ScriptSource initScript, GradleInternal gradle) { .... configurer.apply(gradle); } }
文件路徑:
subprojects\core\src\main\java\org\gradle\configuration\DefaultScriptPluginFactory.java
public void apply(final Object target) { System.out.println("ScriptPluginImpl apply 1"); ... // Pass 1, extract plugin requests and plugin repositories and execute buildscript {}, ignoring (i.e. not even compiling) anything else Class<? extends BasicScript> scriptType = initialPassScriptTarget.getScriptClass(); InitialPassStatementTransformer initialPassStatementTransformer = new InitialPassStatementTransformer(scriptSource, initialPassScriptTarget, documentationRegistry); SubsetScriptTransformer initialTransformer = new SubsetScriptTransformer(initialPassStatementTransformer); String id = INTERNER.intern("cp_" + initialPassScriptTarget.getId()); CompileOperation<PluginRequests> initialOperation = new FactoryBackedCompileOperation<PluginRequests>(id, initialTransformer, initialPassStatementTransformer, pluginRequestsSerializer); ScriptRunner<? extends BasicScript, PluginRequests> initialRunner = compiler.compile(scriptType, initialOperation, baseScope.getExportClassLoader(), Actions.doNothing()); initialRunner.run(target, services); PluginRequests pluginRequests = initialRunner.getData(); PluginManagerInternal pluginManager = initialPassScriptTarget.getPluginManager(); System.out.println("ScriptPluginImpl apply is empty: " + pluginRequests.isEmpty()); pluginRequestApplicator.applyPlugins(pluginRequests, scriptHandler, pluginManager, targetScope); System.out.println("ScriptPluginImpl apply 4"); // Pass 2, compile everything except buildscript {}, pluginRepositories{}, and plugin requests, then run final ScriptTarget scriptTarget = secondPassTarget(target); scriptType = scriptTarget.getScriptClass(); BuildScriptTransformer buildScriptTransformer = new BuildScriptTransformer(scriptSource, scriptTarget); String operationId = scriptTarget.getId(); CompileOperation<BuildScriptData> operation = new FactoryBackedCompileOperation<BuildScriptData>(operationId, buildScriptTransformer, buildScriptTransformer, buildScriptDataSerializer); final ScriptRunner<? extends BasicScript, BuildScriptData> runner = compiler.compile(scriptType, operation, targetScope.getLocalClassLoader(), ClosureCreationInterceptingVerifier.INSTANCE); if (scriptTarget.getSupportsMethodInheritance() && runner.getHasMethods()) { System.out.println("ScriptPluginImpl apply 5"); scriptTarget.attachScript(runner.getScript()); } System.out.println("ScriptPluginImpl apply 6"); if (!runner.getRunDoesSomething()) { System.out.println("ScriptPluginImpl apply 7"); return; } Runnable buildScriptRunner = new Runnable() { public void run() { System.out.println("ScriptPluginImpl apply 8"); runner.run(target, services); } }; System.out.println("ScriptPluginImpl apply 9"); boolean hasImperativeStatements = runner.getData().getHasImperativeStatements(); scriptTarget.addConfiguration(buildScriptRunner, !hasImperativeStatements); }
執行流程:
a. 在DefaultScriptPluginFactory的apply里面主要有兩步 pass1/ pass2
在pass1的時候,處理的文件是
'D:\gradle_jar_cache\caches\3.1-snapshot-1\scripts-remapped\settings_brbxf8awmquo5r6nxrgcmg7fq\iaw3k0vmpedkxsp2gv9xvnom\cp_settingsd7eae713beda1bd9e69f8461da734880\metadata\metadata.bin'
b. 在pass2的時候,處理初始化腳本,如果腳本文件里面有配置,則會到走到'ScriptPluginImpl apply 8' 加載這個腳本的屬性;
如果腳本里面有配置,只是一個空文件,則從'ScriptPluginImpl apply 7'返回。
總結下這個步驟的內容:
a. 加載gradle_user_home下面init.gradle和init.d/目錄下 *.gradle以及gradle home 目錄下的init.d/目錄下的 *.gradle文件
b. 如果有這些文件,而且內容不為空,那么將會加載它們配置的屬性。
比較重要也很令人費解是這行代碼:
scriptCompilerFactory.createCompiler(scriptSource);
這行代碼粗看沒有什么,但是仔細分析后其實大有乾坤!它是在為下一行
initialRunner.run(target, services);
生成可以加載的Java類,最終調用DefaultScriptCompilationHandler.compileToDir來生成類。 生成的類路徑如下:
D:\gradle_jar_cache\caches\3.1-snapshot-1\scripts\df5frxe005h8vnbjcuzkr2g0s\cp_settings\cp_settingsd7eae713beda1bd9e69f8461da734880
執行堆棧如下:
java.lang.Exception: Sandy compile to dir at org.gradle.groovy.scripts.internal.DefaultScriptCompilationHandler.compileToDir(DefaultScriptCompilationHandler.java:97) at org.gradle.groovy.scripts.internal.FileCacheBackedScriptClassCompiler$CompileToCrossBuildCacheAction.execute(FileCacheBackedScriptClassCompiler.java:160) at org.gradle.groovy.scripts.internal.FileCacheBackedScriptClassCompiler$CompileToCrossBuildCacheAction.execute(FileCacheBackedScriptClassCompiler.java:141) at org.gradle.groovy.scripts.internal.FileCacheBackedScriptClassCompiler$Progre***eportingInitializer.execute(FileCacheBackedScriptClassCompiler.java:185) at org.gradle.groovy.scripts.internal.FileCacheBackedScriptClassCompiler$Progre***eportingInitializer.execute(FileCacheBackedScriptClassCompiler.java:164) at org.gradle.cache.internal.DefaultPersistentDirectoryCache$Initializer.initialize(DefaultPersistentDirectoryCache.java:100) at org.gradle.cache.internal.DefaultCacheAccess$2.run(DefaultCacheAccess.java:116) at org.gradle.cache.internal.DefaultFileLockManager$DefaultFileLock.doWriteAction(DefaultFileLockManager.java:179) at org.gradle.cache.internal.DefaultFileLockManager$DefaultFileLock.writeFile(DefaultFileLockManager.java:169) at org.gradle.cache.internal.DefaultCacheAccess.open(DefaultCacheAccess.java:113) at org.gradle.cache.internal.DefaultPersistentDirectoryStore.open(DefaultPersistentDirectoryStore.java:47) at org.gradle.cache.internal.DefaultPersistentDirectoryStore.open(DefaultPersistentDirectoryStore.java:28) at org.gradle.cache.internal.DefaultCacheFactory.doOpen(DefaultCacheFactory.java:83) at org.gradle.cache.internal.DefaultCacheFactory.open(DefaultCacheFactory.java:51) at org.gradle.cache.internal.DefaultCacheRepository$PersistentCacheBuilder.doOpen(DefaultCacheRepository.java:147) at org.gradle.cache.internal.DefaultCacheRepository$AbstractCacheBuilder.open(DefaultCacheRepository.java:121) at org.gradle.groovy.scripts.internal.FileCacheBackedScriptClassCompiler$RemapBuildScriptsAction.execute(FileCacheBackedScriptClassCompiler.java:365) at org.gradle.groovy.scripts.internal.FileCacheBackedScriptClassCompiler$RemapBuildScriptsAction.execute(FileCacheBackedScriptClassCompiler.java:333) at org.gradle.groovy.scripts.internal.FileCacheBackedScriptClassCompiler$Progre***eportingInitializer.execute(FileCacheBackedScriptClassCompiler.java:185) at org.gradle.groovy.scripts.internal.FileCacheBackedScriptClassCompiler$Progre***eportingInitializer.execute(FileCacheBackedScriptClassCompiler.java:164) at org.gradle.cache.internal.DefaultPersistentDirectoryCache$Initializer.initialize(DefaultPersistentDirectoryCache.java:100) at org.gradle.cache.internal.DefaultCacheAccess$2.run(DefaultCacheAccess.java:116) at org.gradle.cache.internal.DefaultFileLockManager$DefaultFileLock.doWriteAction(DefaultFileLockManager.java:179) at org.gradle.cache.internal.DefaultFileLockManager$DefaultFileLock.writeFile(DefaultFileLockManager.java:169) at org.gradle.cache.internal.DefaultCacheAccess.open(DefaultCacheAccess.java:113) at org.gradle.cache.internal.DefaultPersistentDirectoryStore.open(DefaultPersistentDirectoryStore.java:47) at org.gradle.cache.internal.DefaultPersistentDirectoryStore.open(DefaultPersistentDirectoryStore.java:28) at org.gradle.cache.internal.DefaultCacheFactory.doOpen(DefaultCacheFactory.java:83) at org.gradle.cache.internal.DefaultCacheFactory.open(DefaultCacheFactory.java:51) at org.gradle.cache.internal.DefaultCacheRepository$PersistentCacheBuilder.doOpen(DefaultCacheRepository.java:147) at org.gradle.cache.internal.DefaultCacheRepository$AbstractCacheBuilder.open(DefaultCacheRepository.java:121) at org.gradle.groovy.scripts.internal.FileCacheBackedScriptClassCompiler.compile(FileCacheBackedScriptClassCompiler.java:111) at org.gradle.groovy.scripts.internal.CrossBuildInMemoryCachingScriptClassCache.getOrCompile(CrossBuildInMemoryCachingScriptClassCache.java:46) at org.gradle.groovy.scripts.internal.BuildScopeInMemoryCachingScriptClassCompiler.compile(BuildScopeInMemoryCachingScriptClassCompiler.java:48) at org.gradle.groovy.scripts.DefaultScriptCompilerFactory$ScriptCompilerImpl.compile(DefaultScriptCompilerFactory.java:50) at org.gradle.configuration.DefaultScriptPluginFactory$ScriptPluginImpl.apply(DefaultScriptPluginFactory.java:154) at org.gradle.configuration.project.BuildScriptProcessor.execute(BuildScriptProcessor.java:40) at org.gradle.configuration.project.BuildScriptProcessor.execute(BuildScriptProcessor.java:25) at org.gradle.configuration.project.ConfigureActionsProjectEvaluator.evaluate(ConfigureActionsProjectEvaluator.java:34) at org.gradle.configuration.project.LifecycleProjectEvaluator.evaluate(LifecycleProjectEvaluator.java:55) at org.gradle.api.internal.project.DefaultProject.evaluate(DefaultProject.java:573) at org.gradle.api.internal.project.DefaultProject.evaluate(DefaultProject.java:125) at org.gradle.execution.TaskPathProjectEvaluator.configureHierarchy(TaskPathProjectEvaluator.java:42) at org.gradle.configuration.DefaultBuildConfigurer.configure(DefaultBuildConfigurer.java:38) at org.gradle.initialization.DefaultGradleLauncher$2.run(DefaultGradleLauncher.java:154) at org.gradle.internal.Factories$1.create(Factories.java:22) at org.gradle.internal.progress.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:91) at org.gradle.internal.progress.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:53) at org.gradle.initialization.DefaultGradleLauncher.doBuildStages(DefaultGradleLauncher.java:151) at org.gradle.initialization.DefaultGradleLauncher.access$200(DefaultGradleLauncher.java:33) at org.gradle.initialization.DefaultGradleLauncher$1.create(DefaultGradleLauncher.java:114) at org.gradle.initialization.DefaultGradleLauncher$1.create(DefaultGradleLauncher.java:106) at org.gradle.internal.progress.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:91) at org.gradle.internal.progress.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:63) at org.gradle.initialization.DefaultGradleLauncher.doBuild(DefaultGradleLauncher.java:106) at org.gradle.initialization.DefaultGradleLauncher.run(DefaultGradleLauncher.java:92) at org.gradle.launcher.exec.GradleBuildController.run(GradleBuildController.java:67) at org.gradle.tooling.internal.provider.ExecuteBuildActionRunner.run(ExecuteBuildActionRunner.java:31) at org.gradle.launcher.exec.ChainingBuildActionRunner.run(ChainingBuildActionRunner.java:43) at org.gradle.launcher.exec.InProcessBuildActionExecuter.execute(InProcessBuildActionExecuter.java:42) at org.gradle.launcher.exec.InProcessBuildActionExecuter.execute(InProcessBuildActionExecuter.java:26) at org.gradle.tooling.internal.provider.ContinuousBuildActionExecuter.execute(ContinuousBuildActionExecuter.java:79) at org.gradle.tooling.internal.provider.ContinuousBuildActionExecuter.execute(ContinuousBuildActionExecuter.java:51) at org.gradle.launcher.cli.RunBuildAction.run(RunBuildAction.java:54) at org.gradle.internal.Actions$RunnableActionAdapter.execute(Actions.java:173) at org.gradle.launcher.cli.CommandLineActionFactory$ParseAndBuildAction.execute(CommandLineActionFactory.java:250) at org.gradle.launcher.cli.CommandLineActionFactory$ParseAndBuildAction.execute(CommandLineActionFactory.java:217) at org.gradle.launcher.cli.JavaRuntimeValidationAction.execute(JavaRuntimeValidationAction.java:33) at org.gradle.launcher.cli.JavaRuntimeValidationAction.execute(JavaRuntimeValidationAction.java:24) at org.gradle.launcher.cli.ExceptionReportingAction.execute(ExceptionReportingAction.java:33) at org.gradle.launcher.cli.ExceptionReportingAction.execute(ExceptionReportingAction.java:22) at org.gradle.launcher.cli.CommandLineActionFactory$WithLogging.execute(CommandLineActionFactory.java:210) at org.gradle.launcher.cli.CommandLineActionFactory$WithLogging.execute(CommandLineActionFactory.java:174) at org.gradle.launcher.Main.doAction(Main.java:33) at org.gradle.launcher.bootstrap.EntryPoint.run(EntryPoint.java:45) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:483) at org.gradle.launcher.bootstrap.ProcessBootstrap.runNoExit(ProcessBootstrap.java:60) at org.gradle.launcher.bootstrap.ProcessBootstrap.run(ProcessBootstrap.java:37) at org.gradle.launcher.GradleMain.main(GradleMain.java:24)
接下來,繼續往下面看Load步驟的第二個步驟findAndLoadSettings.
// Build `buildSrc`, load settings.gradle, and construct composite (if appropriate) settings = settingsLoader.findAndLoadSettings(gradle);
四. Load.findAndLoadSettings
settings = settingsLoader.findAndLoadSettings(gradle);
首先settingsLoader使用了裝飾者模式,從外到內包裝順序是:
public class NotifyingSettingsLoader implements SettingsLoader { private final SettingsLoader settingsLoader; ... @Override public SettingsInternal findAndLoadSettings(GradleInternal gradle) { SettingsInternal settings = settingsLoader.findAndLoadSettings(gradle); gradle.getBuildListenerBroadcaster().settingsEvaluated(settings); buildLoader.load(settings.getRootProject(), settings.getDefaultProject(), gradle, settings.getRootClassLoaderScope()); gradle.getBuildListenerBroadcaster().projectsLoaded(gradle); return settings; } } public class CompositeBuildSettingsLoader implements SettingsLoader { private final SettingsLoader delegate; ... @Override public SettingsInternal findAndLoadSettings(GradleInternal gradle) { SettingsInternal settings = delegate.findAndLoadSettings(gradle); ... } } /** * Handles locating and processing setting.gradle files. Also deals with the buildSrc module, since that modules is * found after settings is located, but needs to be built before settings is processed. */ public class DefaultSettingsLoader implements SettingsLoader { ... @Override public SettingsInternal findAndLoadSettings(GradleInternal gradle) { ... SettingsInternal settings = findSettingsAndLoadIfAppropriate(gradle, startParameter); ... ProjectSpec spec = ProjectSpecs.forStartParameter(startParameter, settings); System.out.println(" spec: " + spec); if (spec.containsProject(settings.getProjectRegistry())) { System.out.println("spec.containsProject"); setDefaultProject(spec, settings); return settings; } // Try again with empty settings StartParameter noSearchParameter = startParameter.newInstance(); noSearchParameter.useEmptySettings(); settings = findSettingsAndLoadIfAppropriate(gradle, noSearchParameter); // Set explicit build file, if required if (noSearchParameter.getBuildFile() != null) { ProjectDescriptor rootProject = settings.getRootProject(); rootProject.setBuildFileName(noSearchParameter.getBuildFile().getName()); } setDefaultProject(spec, settings); return settings; }
NotifyingSettingsLoader首先會根據裝飾者模式逐個的調用進去,所以DefaultSettingsLoader.findAndLoadSettings方法,然后在回頭看NotifyingSettingsLoader.findAndLoadSettings的其他代碼。
DefaultSettingsLoader根據注釋,它是要處理項目目錄下的setting.gradle文件,同時處理buildSrc模塊,這個好像一般項目沒有。
所以,可以先看DefaultSettingsLoader.findAndLoadSettings方法。
1. DefaultSettingsLoader
文件路徑:
subprojects\core\src\main\java\org\gradle\initialization\DefaultSettingsLoader.java
@Override public SettingsInternal findAndLoadSettings(GradleInternal gradle) { StartParameter startParameter = gradle.getStartParameter(); System.out.println("DefaultSettingsLoader.findAndLoadSettings startParameter: " + startParameter + " gradle: " + gradle); SettingsInternal settings = findSettingsAndLoadIfAppropriate(gradle, startParameter); System.out.println(" settings: " + settings); ProjectSpec spec = ProjectSpecs.forStartParameter(startParameter, settings); System.out.println(" spec: " + spec); if (spec.containsProject(settings.getProjectRegistry())) { System.out.println("spec.containsProject"); setDefaultProject(spec, settings); return settings; } // Try again with empty settings StartParameter noSearchParameter = startParameter.newInstance(); noSearchParameter.useEmptySettings(); settings = findSettingsAndLoadIfAppropriate(gradle, noSearchParameter); // Set explicit build file, if required if (noSearchParameter.getBuildFile() != null) { ProjectDescriptor rootProject = settings.getRootProject(); rootProject.setBuildFileName(noSearchParameter.getBuildFile().getName()); } setDefaultProject(spec, settings); return settings; } private SettingsInternal findSettingsAndLoadIfAppropriate(GradleInternal gradle, ... return settingsProcessor.process(gradle, settingsLocation, buildSourceClassLoader, startParameter); } 2. 首先看findSettingsAndLoadIfAppropriate 這個方法。看名字應該是尋找Settings并嘗試加載它。 它調用的是settingsProcessor.process 這個settingsProcessor又使用了裝飾者模式,共有3個類。 public class NotifyingSettingsProcessor implements SettingsProcessor {} public class PropertiesLoadingSettingsProcessor implements SettingsProcessor { public SettingsInternal process(GradleInternal gradle, SettingsLocation settingsLocation, ClassLoaderScope baseClassLoaderScope, StartParameter startParameter) { System.out.println("PropertiesLoadingSettingsProcessor run"); propertiesLoader.loadProperties(settingsLocation.getSettingsDir()); return processor.process(gradle, settingsLocation, baseClassLoaderScope, startParameter); } } public class ScriptEvaluatingSettingsProcessor implements SettingsProcessor { public SettingsInternal process(GradleInternal gradle, SettingsLocation settingsLocation, ClassLoaderScope baseClassLoaderScope, StartParameter startParameter) { System.out.println("Script Process process"); Clock settingsProcessingClock = new Clock(); Map<String, String> properties = propertiesLoader.mergeProperties(Collections.<String, String>emptyMap()); SettingsInternal settings = settingsFactory.createSettings(gradle, settingsLocation.getSettingsDir(), settingsLocation.getSettingsScriptSource(), properties, startParameter, baseClassLoaderScope); applySettingsScript(settingsLocation, settings); LOGGER.debug("Timing: Processing settings took: {}", settingsProcessingClock.getTime()); return settings; } }
真的,gradle源代碼使用了很多裝飾者模式。
3. 首先看看PropertiesLoadingSettingsProcessor.process方法
文件路徑:subprojects\core\src\main\java\org\gradle\initialization\PropertiesLoadingSettingsProcessor.java
public class PropertiesLoadingSettingsProcessor implements SettingsProcessor { ... public SettingsInternal process(GradleInternal gradle, SettingsLocation settingsLocation, ClassLoaderScope baseClassLoaderScope, StartParameter startParameter) { System.out.println("PropertiesLoadingSettingsProcessor run"); propertiesLoader.loadProperties(settingsLocation.getSettingsDir()); return processor.process(gradle, settingsLocation, baseClassLoaderScope, startParameter); } }
文件路徑:
subprojects\core\src\main\java\org\gradle\initialization\DefaultGradlePropertiesLoader.java
public static final String SYSTEM_PROP_PREFIX = "systemProp"; String ENV_PROJECT_PROPERTIES_PREFIX = "ORG_GRADLE_PROJECT_"; String SYSTEM_PROJECT_PROPERTIES_PREFIX = "org.gradle.project."; public void loadProperties(File settingsDir) { loadProperties(settingsDir, startParameter, getAllSystemProperties(), getAllEnvProperties()); } void loadProperties(File settingsDir, StartParameter startParameter, Map<String, String> systemProperties, Map<String, String> envProperties) { defaultProperties.clear(); overrideProperties.clear(); addGradleProperties(defaultProperties, new File(settingsDir, Project.GRADLE_PROPERTIES)); addGradleProperties(overrideProperties, new File(startParameter.getGradleUserHomeDir(), Project.GRADLE_PROPERTIES)); setSystemProperties(startParameter.getSystemPropertiesArgs()); overrideProperties.putAll(getEnvProjectProperties(envProperties)); overrideProperties.putAll(getSystemProjectProperties(systemProperties)); for (String key : systemProperties.keySet()) { System.out.println("system properties, key: " + key + " value: " + systemProperties.get(key)); } for (String key : envProperties.keySet()) { System.out.println("env properties, key: " + key + " value: " + envProperties.get(key)); } overrideProperties.putAll(startParameter.getProjectProperties()); } private void setSystemProperties(Map<String, String> properties) { addSystemPropertiesFromGradleProperties(defaultProperties); addSystemPropertiesFromGradleProperties(overrideProperties); System.getProperties().putAll(properties); } private void addSystemPropertiesFromGradleProperties(Map<String, String> properties) { for (String key : properties.keySet()) { if (key.startsWith(Project.SYSTEM_PROP_PREFIX + '.')) { System.setProperty(key.substring((Project.SYSTEM_PROP_PREFIX + '.').length()), properties.get(key)); } } }
在loadProperties方法里面,它首先調用addGradleProperties方法分別把
a. 項目路徑下面的gradle.properties
b. gradle_user_home路徑下面的gradle.properties
兩個文件分別讀取到defaultProperties和overrideProperties兩個map中。
比如,像這種屬性:
org.gradle.jvmargs=-Xmx1536m # When configured, Gradle will run in incubating parallel mode. # This option should only be used with decoupled projects. More details, visit # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects # org.gradle.parallel=true
然后調用addSystemProperties方法把項目目錄和gradle_user_home目錄gradle.properties兩個文件里面'systemProp'開頭的屬性設置到系統屬性里面;同時把讀取到的系統屬性也設置進去。
再然后調用overrideProperties.putAll把環境變量中'ORG_GRADLE_PROJECT_'和系統屬性中'org.gradle.project.'開頭的變量,存放到overrideProperties map集合中。
最后,把projectProperties屬性加入到overrideProperties map集合中。
4. 繼續看ScriptEvaluatingSettingsProcessor.process
因為是裝飾者模式,所以在調用完PropertiesLoadingSettingsProcessor.process之后,就會繼續調用它里面包裝的ScriptEvaluatingSettingsProcessor.process,代碼如下:
文件路徑:subprojects\core\src\main\java\org\gradle\initialization\ScriptEvaluatingSettingsProcessor.java
public class ScriptEvaluatingSettingsProcessor implements SettingsProcessor { ... public SettingsInternal process(GradleInternal gradle, SettingsLocation settingsLocation, ClassLoaderScope baseClassLoaderScope, StartParameter startParameter) { ... Map<String, String> properties = propertiesLoader.mergeProperties(Collections.<String, String>emptyMap()); SettingsInternal settings = settingsFactory.createSettings(gradle, settingsLocation.getSettingsDir(), settingsLocation.getSettingsScriptSource(), properties, startParameter, baseClassLoaderScope); applySettingsScript(settingsLocation, settings); ... } ... //文件路徑:subprojects\core\src\main\java\org\gradle\initialization\DefaultGradlePropertiesLoader.java public Map<String, String> mergeProperties(Map<String, String> properties) { Map<String, String> result = new HashMap<String, String>(); result.putAll(defaultProperties); result.putAll(properties); result.putAll(overrideProperties); return result; } private void applySettingsScript(SettingsLocation settingsLocation, final SettingsInternal settings) { ScriptSource settingsScriptSource = settingsLocation.getSettingsScriptSource(); ClassLoaderScope settingsClassLoaderScope = settings.getClassLoaderScope(); ScriptHandler scriptHandler = scriptHandlerFactory.create(settingsScriptSource, settingsClassLoaderScope); ScriptPlugin configurer = configurerFactory.create(settingsScriptSource, scriptHandler, settingsClassLoaderScope, settings.getRootClassLoaderScope(), true); System.out.println("applySettingsScript configurer: " + configurer); configurer.apply(settings); } }
首先呢,把上一步加載好的屬性都merge在一起,放到properties里面。
然后調用configurer.apply(settings)設置項目目錄下settings.gradle文件屬性
那DefaultSettingsLoader.findAndLoadSettings就基本結束了,回過頭去看看NotifyingSettingsLoader.findAndLoadSettings的剩余部分代碼。
5. 繼續看NotifyingSettingsLoader.
public class NotifyingSettingsLoader implements SettingsLoader { ... @Override public SettingsInternal findAndLoadSettings(GradleInternal gradle) { SettingsInternal settings = settingsLoader.findAndLoadSettings(gradle); ... gradle.getBuildListenerBroadcaster().settingsEvaluated(settings); buildLoader.load(settings.getRootProject(), settings.getDefaultProject(), gradle, settings.getRootClassLoaderScope()); gradle.getBuildListenerBroadcaster().projectsLoaded(gradle); return settings; } }
首先發送一個事件通知settingsEvaulated,就是settings配置文件處理完畢。
然后調用buildLoader.load(xxx)
buildLoader又是使用了一個裝飾者模式!從外到內包裝如下:
public class ProjectPropertySettingBuildLoader implements BuildLoader { ... public void load(ProjectDescriptor rootProjectDescriptor, ProjectDescriptor defaultProject, GradleInternal gradle, ClassLoaderScope classLoaderScope) { buildLoader.load(rootProjectDescriptor, defaultProject, gradle, classLoaderScope); setProjectProperties(gradle.getRootProject(), new CachingPropertyApplicator()); } } public class InstantiatingBuildLoader implements BuildLoader { private final IProjectFactory projectFactory; public InstantiatingBuildLoader(IProjectFactory projectFactory) { this.projectFactory = projectFactory; } /** * Creates the {@link org.gradle.api.internal.GradleInternal} and {@link ProjectInternal} instances for the given root project, ready for the projects to be configured. */ public void load(ProjectDescriptor rootProjectDescriptor, ProjectDescriptor defaultProject, GradleInternal gradle, ClassLoaderScope baseClassLoaderScope) { createProjects(rootProjectDescriptor, gradle, baseClassLoaderScope); attachDefaultProject(defaultProject, gradle); } private void attachDefaultProject(ProjectDescriptor defaultProject, GradleInternal gradle) { gradle.setDefaultProject(gradle.getRootProject().getProjectRegistry().getProject(defaultProject.getPath())); } private void createProjects(ProjectDescriptor rootProjectDescriptor, GradleInternal gradle, ClassLoaderScope baseClassLoaderScope) { ProjectInternal rootProject = projectFactory.createProject(rootProjectDescriptor, null, gradle, baseClassLoaderScope.createChild("root-project"), baseClassLoaderScope); System.out.println("create project, rootProject: " + rootProject); gradle.setRootProject(rootProject); addProjects(rootProject, rootProjectDescriptor, gradle, baseClassLoaderScope); } }
那上面這段代碼的作用就是配置gradle project層級關系,比如上層是項目根目錄,也就是rootProject。
然后試各個模塊,包括主模塊app
日志如下:
createProject buildFile: E:\work_space\Android-Prototype\build.gradle parent: null createProject buildFile: E:\work_space\Android-Prototype\app\build.gradle parent: root project 'Android-Prototype' createProject buildFile: E:\work_space\Android-Prototype\pushsdk\build.gradle parent: root project 'Android-Prototype' createProject buildFile: E:\work_space\Android-Prototype\moduletest\build.gradle parent: root project 'Android-Prototype'
然后發送project loaded通知。
gradle.getBuildListenerBroadcaster().projectsLoaded(gradle);
至此,Load步驟結束!
if (stage == null) { // Evaluate init scripts initScriptHandler.executeScripts(gradle); // Build `buildSrc`, load settings.gradle, and construct composite (if appropriate) settings = settingsLoader.findAndLoadSettings(gradle); stage = Stage.Load; }
下一篇文章來繼續Configure過程。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。