假设有如下的场景:你需要在运行时动态地配置另一个已写好、已存在的 Plugin,应该怎么做?例如,我们自己写的 Plugin 希望对 JavaPlugin 的 sourceSet
进行动态配置,即在 Configure 阶段动态替换 JavaPlugin 默认的 sourceSet
配置。
public class InhouseConventionJavaPlugin implements Plugin<Project> {
@Override
public void apply(Project target) {
target.getPlugins().apply(JavaPlugin.class);
JavaPluginConvention javaConvention =
target.getConvention().getPlugin(JavaPluginConvention.class);
SourceSet main = javaConvention.getSourceSets().getByName(SourceSet.MAIN_SOURCE_SET_NAME);
System.out.println("before " + main.getJava().getSrcDirs());
main.getJava().setSrcDirs(Arrays.asList("source"));
System.out.println("after " + main.getJava().getSrcDirs());
}
}
在 build.gradle
中只写 apply plugin: InhouseConventionJavaPlugin
,而不要再 apply plugin: 'java'
。
执行 gradle tasks --all
让上面 Plugin 代码执行:

通过我们打的 log 可以看到,我们已经将 JavaPlugin 的
SourceSet
由 src/main/java 变为了 source。通过 idea 的识别我们也可以看得出来,原本 src/main/java/Test.java 文件 idea 已不再识别:

改进
上面的 Plugin 其实有个问题:我们在自己的 Plugin 里主动 apply
了 JavaPlugin。但是从设计上来讲,我们自己的 Plugin 其实应该是和 JavaPlugin 解耦的,即只有当开发者真的使用了 JavaPlugin 我们才对 JavaPlugin 进行以上动态配置。修改代码如下:
public class InhouseConventionJavaPlugin implements Plugin<Project> {
@Override
public void apply(Project target) {
target.getPlugins().withType(JavaPlugin.class, javaPlugin -> {
JavaPluginConvention javaConvention =
target.getConvention().getPlugin(JavaPluginConvention.class);
SourceSet main = javaConvention.getSourceSets().getByName(SourceSet.MAIN_SOURCE_SET_NAME);
System.out.println("before " + main.getJava().getSrcDirs());
main.getJava().setSrcDirs(Arrays.asList("source"));
System.out.println("after " + main.getJava().getSrcDirs());
});
}
}
我们通过监听 JavaPlugin 被添加的回调来完成我们的动态配置。这样当我们只 apply plugin: InhouseConventionJavaPlugin
时,执行 gradle tasks --all
就不会看到有打印 log 信息。 idea 中也识别不到 sources root:

只有当我们同时
apply plugin: 'java'
才会看到 source 目录被标记为了 sources root。
网友评论