Gradle 进阶 第八篇
宁为玉碎,不为瓦全
Gradle Project 下卷
上一章讲到 Gradle 的 ConfigurationContainer,ConfigurationContainer 里面包含了一些系列的 Configuration,而 Configuration 又继承了 FileCollection 接口。其实现类 DefaultConfiguration 中包括了对外发布的一个集合,以及构建依赖的一个集合。以供 project 管理依赖,并且对外提供构建好的 Artifact。
public class DefaultConfiguration extends AbstractFileCollection implements ConfigurationInternal, MutationValidator {
...
private DefaultDependencySet allDependencies;
...
private DefaultPublishArtifactSet allArtifacts;
}
ArtifactHandler
ArtifactHandler 这个类用于定义要发布的 artifact,并将它们添加到配置中。创建发布工件并不意味着要创建存档。创建的是表示要发布的文件的域对象以及如何发布的信息(这是源码里注解的翻译),这个类创建于 2009 年,gradle 后面又加入了 Ivy 以及 Maven (2013)作真正的发布逻辑,所以从源码上 ArtifactHandler 更多的是暴露了在脚本中往 configuration 里添加 artifact 的能力。
这里举一个栗子:
configurations {
//declaring new configuration that will be used to associate with artifacts
schema
}
task schemaJar(type: Jar) {
//some imaginary task that creates a jar artifact with some schema
}
//associating the task that produces the artifact with the configuration
artifacts {
//configuration name and the task:
schema schemaJar
}
栗子里面首先创建一个名叫 schema 的 configuration,接着创建了一个 task,task 主要是用来生成 artifact,最后调用 DefaultProject 的 artifacts 方法传入一个闭包作为参数。
其实 ArtifactHandler 接口只有三个方法,每个方法都有一个 String 类型的 configurationName 参数指定 configuration,还有一个 Object 类型的 artifactNotation,这里对 artifactNotation 有一定的限制:
- PublishArtifact
- AbstractArchiveTask
- RegularFile or Directiory
- File
- Map
public interface ArtifactHandler {
PublishArtifact add(String configurationName, Object artifactNotation);
PublishArtifact add(String configurationName, Object artifactNotation, Closure configureClosure);
PublishArtifact add(String configurationName, Object artifactNotation, Action<? super ConfigurablePublishArtifact> configureAction);
}
这里需要注意一点,在 gradle 源码中有两个 artifact 接口, PublishArtifact 和 PublicationArtifact,这里所讨论的是 PublishArtifact,而 PublicationArtifact 以及其子接口 MavenArtifact 和 IvyArtifact 会在后面讲发布到仓库的时候讲解。
这里就会有一个疑问,加入 configuration 的这些 artifacts 到底在什么时候去使用。这里以 BasePlugin 举一个栗子:
public class BasePlugin implements Plugin<Project> {
public static final String ASSEMBLE_TASK_NAME = LifecycleBasePlugin.ASSEMBLE_TASK_NAME;/// "assemble"
private void configureAssemble(final ProjectInternal project) {
project.getTasks().named(ASSEMBLE_TASK_NAME, task -> {
task.dependsOn(task.getProject().getConfigurations().getByName(Dependency.ARCHIVES_CONFIGURATION).getAllArtifacts().getBuildDependencies());
});
}
}
这里我们看到在 apply 了 BasePlugin 之后,会调用到 configureAssemble 这个函数,在里面,创建了 assemble 的 Task,并且将这个 task 依赖了当前 Project 的 archives configuration 的所有 artifacts 的依赖。这句话有点绕,需要对着源码体会。
ExtensibleDynamicObject
ExtensibleDynamicObject 我在第二章讲过了,在动态调用系统中详细描述了,这个类的作用,有不清楚的可以回看一下,这里就不在赘述。