写点什么

Gradle 庖丁解牛(构建生命周期核心委托对象创建源码浅析)

用户头像
Android架构
关注
发布于: 刚刚

public class DefaultGradleLauncherFactory implements GradleLauncherFactory {


......


private DefaultGradleLauncher doNewInstance(StartParameter startParameter, GradleLauncher parent,


BuildCancellationToken cancellationToken, BuildRequestMetaData requestMetaData, BuildEventConsumer buildEventConsumer, final BuildSessionScopeServices sessionScopeServices, List<?> servicesToStop) {


BuildScopeServices serviceRegistry = BuildScopeServices.forSession(sessionScopeServices);


......


//Gradle 框架自身初始化 OK 以后第一次调用时 parent 为 null。


GradleInternal parentBuild = parent == null ? null : parent.getGradle();


//创建一个 DefaultGradle 对象,也就是 Gradle 的实现,其中最重要的参数就是 startParameter,包含了我们执行 gradle 命令时携带的参数。


GradleInternal gradle = serviceRegistry.get(Instantiator.class).newInstance(DefaultGradle.class, parentBuild, startParameter, serviceRegistry.get(ServiceRegistryFactory.class));


//把实例化的 Gradle 对象传入 DefaultGradleLauncher 实例。


DefaultGradleLauncher gradleLauncher = new DefaultGradleLauncher(


gradle,


......


);


nestedBuildFactory.setParent(gradleLauncher);


return gradleLauncher;


}


......


}


上面就是我们说的 Gradle 实例创建时机,可见 Gradle 实例的实现其实是 DefaultGradle 对象,也就是 Gradle 官方 DSL 文档的 Some basics 中描述的 init script 的委托对象 Gradle。由此在我们编写 Gradle 脚本时获取 Gradle 实例后进行的设置其实都是在对该对象进行设置咯,具体编写参考 Gradle 实例对象 DSL ReferenceGradle 对象 API 文档 或者框架源码。这没啥可说的,和写 Java 一样咯。


3-2 Settings 对象浅析




上面已经介绍


《Android学习笔记总结+最新移动架构视频+大厂安卓面试真题+项目实战源码讲义》
浏览器打开:qq.cn.hn/FTe 免费领取
复制代码


了委托实例对象 Gradle 的创建时机,这里再来简单看看委托实例对象 Settings 的创建和作用;老规矩,先看下 Settings 对象的继承关系,如下:


public class DefaultSettings extends AbstractPluginAware implements SettingsInternal


public interface SettingsInternal extends Settings


public interface Settings extends PluginAware


纳尼?看起来和 Gradle 对象关系比较类似,其共同祖先都是 PluginAware 接口,先不管这些,我们先去看看他在哪创建的吧。


在上面第二小节的构建生命周期宏观浅析中我们分析了执行 gradle taskName 命令进行 Gradle 框架自身初始化以后会执行到 DefaultGradleLauncher 的 doBuildStages(Stage upTo) 方法,该方法里有这么一行调用,如下:


//初始化构建时第一次状态初始化会执行该行代码


// Build buildSrc, load settings.gradle, and construct composite (if appropriate)


settings = settingsLoader.findAndLoadSettings(gradle);


这里的 settingsLoader 和 gradle 实例都是创建 DefaultGradleLauncher 实例时传入的,关于 gradle 前面已经分析了,settingsLoader 其实是在 DefaultGradleLauncherFactory 创建 DefaultGradleLauncher 实例前通过 settingsLoaderFactory.forTopLevelBuild() 创建的,也就是 DefaultSettingsLoaderFactory 中创建,如下:


public class DefaultSettingsLoaderFactory implements SettingsLoaderFactory {


......


//这里是调用 Top Settings 创建咯,还有个 forNestedBuild 创建的。


@Override


public SettingsLoader forTopLevelBuild() {


//包装三层调用,实质先调用了 DefaultSettingsLoader 的 findAndLoadSettings(gradle)方法


return new NotifyingSettingsLoader(


new CompositeBuildSettingsLoader(


new DefaultSettingsLoader(


settingsFinder,


settingsProcessor,


buildSourceBuilder


),


buildServices


),


buildLoader);


}


......


}


得到 SettingsLoader 对象以后在 DefaultGradleLauncher 的 doBuildStages(Stage upTo) 方法中就创建了我们要说的 Settings 委托实例对象,至于创建的过程无非就是尝试依据命令行参数进行匹配查找譬如 settings.gradle 文件等(感兴趣的可以去看看 DefaultSettingsLoader 的 findAndLoadSettings 方法中的 findSettingsAndLoadIfAppropriate(gradle, startParameter); 调用实现)。


可见 Settings 实例的实现其实是 DefaultSettings 对象,也就是 Gradle 官方 DSL 文档的 Some basics 中描述的 settings script 的委托对象 Settings。由此在我们编写 Gradle 脚本时获取 Settings 实例后进行的设置其实都是在对该对象进行设置咯,具体编写参考 Settings 实例对象 DSL ReferenceSettings 对象 API 文档 或者框架源码。不过关于 Settings 委托对象的使用和核心说明除过看上面提到的官方文档以外,Settings.java 文件的注释也很言简意赅,如下:


/**


  • <p>Declares the configuration required to instantiate and configure the hierarchy of {@link

  • org.gradle.api.Project} instances which are to participate in a build.</p>

  • <p>There is a one-to-one correspondence between a <code>Settings</code> instance and a <code>{@value

  • #DEFAULT_SETTINGS_FILE}</code> settings file. Before Gradle assembles the projects for a build, it creates a

  • <code>Settings</code> instance and executes the settings file against it.</p>

  • <h3>Assembling a Multi-Project Build</h3>

  • <p>One of the purposes of the <code>Settings</code> object is to allow you to declare the projects which are to be

  • included in the build. You add projects to the build using the {@link #include(String[])} method. There is always a

  • root project included in a build. It is added automatically when the <code>Settings</code> object is created. The

  • root project's name defaults to the name of the directory containing the settings file. The root project's project

  • directory defaults to the directory containing the settings file.</p>

  • <p>When a project is included in the build, a {@link ProjectDescriptor} is created. You can use this descriptor to

  • change the default values for several properties of the project.</p>

  • <h3>Using Settings in a Settings File</h3>

  • <h4>Dynamic Properties</h4>

  • <p>In addition to the properties of this interface, the {@code Settings} object makes some additional read-only

  • properties available to the settings script. This includes properties from the following sources:</p>

  • <ul>

  • <li>Defined in the {@value org.gradle.api.Project#GRADLE_PROPERTIES} file located in the settings directory of the

  • build.</li>

  • <li>Defined the {@value org.gradle.api.Project#GRADLE_PROPERTIES} file located in the user's {@code .gradle}

  • directory.</li>

  • <li>Provided on the command-line using the -P option.</li>

  • </ul>


*/


3-3 Project 对象浅析




上面已经介绍了委托实例对象 Gradle、Settings 的创建时机,这里再来简单看看委托实例对象 Project 的创建和作用;老规矩,先看下 Project 对象的继承关系,如下:


public class DefaultProject extends AbstractPluginAware implements ProjectInternal, DynamicObjectAware


public interface ProjectInternal extends Project, ProjectIdentifier, FileOperations, ProcessOperations, DomainObjectContext, DependencyMetaDataProvider, ModelRegistryScope, PluginAwareInternal


public interface Project extends Comparable<Project>, ExtensionAware, PluginAware


纳尼?看起来继承关系略显复杂,但是还是挺直观的,先不管这些,我们从这里看出 Project 接口的实现实例是 DefaultProject 就行。关于这货在哪创建我想眼尖的人已经知道答案了,前面我们分析 Settings 对象时最后有段源码注释还记得么,如下(Settings.java):


You add projects to the build using the {@link #include(String[])} method.


When a project is included in the build, a {@link ProjectDescriptor} is created.


You can use this descriptor to change the default values for several properties


of the project.


通过这段注释可以发现,其实 Project 创建很有可能依赖于 ProjectDescriptor,而 ProjectDescriptor 又是我们在 settings.gradle 中添加的 module 工程。所以我们还是先把目光挪到上面分析 Settings 创建时的 settingsLoader.findAndLoadSettings(gradle);调用,可以发现 NotifyingSettingsLoader 的 findAndLoadSettings(GradleInternal gradle) 方法中调用了如下语句:


public SettingsInternal findAndLoadSettings(GradleInternal gradle) {


SettingsInternal settings = settingsLoader.findAndLoadSettings(gradle);


......


buildLoader.load(settings.getRootProject(), settings.getDefaultProject(), gradle, settings.getRootClassLoaderScope());


gradle.getBuildListenerBroadcaster().projectsLoaded(gradle);


return settings;


}


可以看见对应的一个 Settings 里关联的 ProjectDescriptor 都生成了对应的 Project 对象。可见 Project 实例的实现其实是 DefaultProject 对象(是 Settings 里面对应 ProjectDescriptor 进行转换生成),也就是 Gradle 官方 DSL 文档的 Some basics 中描述的 build script 的委托对象 Project。由此在我们编写 Gradle 脚本时获取对应不同的 Project 实例后进行的设置其实都是在对该对象进行设置咯,具体编写参考 Project 实例对象 DSL ReferenceProject 对象 API 文档 或者框架源码。不过关于 Project 委托对象的使用和核心说明除过看上面提到的官方文档以外,Project.java 文件的注释也很言简意赅,值得推荐。


【工匠若水 http://blog.csdn.net/yanbober 未经允许严禁转载,请尊重作者劳动成果。私信联系我


4 抛开源码浅析回到常规脚本编写总结


======================


上面分析了一堆源码其实无非就是为了让我们编写脚本时能够做到胸有成竹,不至于被牵着鼻子配,所以有了上面的分析我们可以在我们各个 Gradle 脚本中加入类似如下 log 进行实例对象哈希码测试(不同 gradle 脚本 log 写法可能有出入),如下:

用户头像

Android架构

关注

还未添加个人签名 2021.10.31 加入

还未添加个人简介

评论

发布
暂无评论
Gradle 庖丁解牛(构建生命周期核心委托对象创建源码浅析)