第一章:Gradle 插件基本定义
1.1 概述
- 不同的 Gradle 插件都会提供有不同的 Gradle 任务,之前使用的所有插件都是系统提供的或者第三方提供的完整插件,但是在实际项目开发中可以由开发者定义自己的开发插件,对于插件的开发有三种定义方式:
- ① 构建脚本中:所有的 Gradle 项目中都有一个 build.gradle 配置文件,可以直接在这文件里面定义插件类。
- ② buildSrc 目录:类似于项目中的源代码 src 目录,只不过里面保存的是插件的代码。
- ③ 单独项目:是一个独立的项目,需要将其发布到公共的仓库之中。
- 本次讲解先通过一个简单的构建脚本实现相关插件的定义。
- 插件中提供的就是任务,这个任务的定义是需要有结构上的要求的,如果要想定义插件,必须让插件对应的类去实现一个 Plugin 接口,此接口的定义如下:
package org.gradle.api;
public interface Plugin<T> {
void apply(T var1);
}
- 需要为其设置一个泛型参数
Plugin<T>
,既然现在要自定义一个项目的插件,那么就可以直接传递 Project 的相关信息,而所有和项目环境有关的信息都可以通过 Project 接口来获取:
package org.gradle.api;
public interface Project extends Comparable<Project>, ExtensionAware, PluginAware {
String DEFAULT_BUILD_FILE = "build.gradle";
String PATH_SEPARATOR = ":";
String DEFAULT_BUILD_DIR_NAME = "build";
String GRADLE_PROPERTIES = "gradle.properties";
String SYSTEM_PROP_PREFIX = "systemProp";
String DEFAULT_VERSION = "unspecified";
String DEFAULT_STATUS = "release";
Project getRootProject();
File getRootDir();
File getBuildDir();
void setBuildDir(File var1);
void setBuildDir(Object var1);
File getBuildFile();
...
}
1.2 定义插件
- 直接在 build.gradle 配置文件中定义插件:
class CustomPlugin implements Plugin<Project> {
@Override
void apply(Project project) {
project.task('message', group: 'com.github.fairy.era') {
doLast {
println '你好啊,Gradle'
}
}
}
}
1.3 使用插件
- 插件定义完成之后,可以使用 apply 的语法结构启用插件,修改 build.gradle 配置文件:
apply plugin: CustomPlugin
1.4 执行任务
- 插件配置完成之后 CustomPlugin 之中定义的所有任务就可以在当前项目中使用了,直接任务即可。
- 程序执行命令:
gradle message
- 程序执行结果:
11:13:49: 正在执行 'message'…
> Task :message
你好啊,Gradle
BUILD SUCCESSFUL in 204ms
1 actionable task: 1 executed
11:13:49: 执行完成 'message'。
- 此时就成功的实现了一个插件,但是这个插件和之前使用的环境还是有一些区别的,因为传统的插件肯定要通过 plugins 的配置来进行引用,而现在的插件只能够在当前的配置文件中使用。
第二章:Gradle 自定义插件管理
2.1 概述
- 虽然已经成功的实现了一个 Gradle 开发插件,但是从另外的角度讲此时的代码也存在如下的问题:
- ① 在项目中如果将所有插件的源代码都定义在了 build.gradle 配置文件里面,天长日久,build.gradle 文件将会越来越庞大。
- ② 在实现所有的自定义插件中也需要进行有效的结构上的管理。
- 所以,从实际的开发角度讲,应该考虑将所有的插件放在统一的包中进行管理,现在可以通过两种方式进行这种插件的管理:Groovy 语法和 Java 语法,本次使用的是 Groovy 的形式实现插件管理。
2.2 目录创建
- 如果要想在代码中对所有的插件进行管理,则需要在项目根目录下创建一个
buildSrc
的目录。
如果按照 IDEA 正常使用的原则来说,此时可以自动帮助用户进行该目录的识别(这个目录就是一个独立的模块),如果不能识别,那就通过 IDEA 中的 Gradle 工具面板多刷新几次。
2.2 源代码目录
- buildSrc 是一个独立的项目,所有的项目代码就需要用户手动建立目录 src/main/groovy ,并且在 IDEA 的 Gradle 工具面板多刷新几次。
2.3 Groovy 程序
- 创建一个 Groovy 的程序,该程序就是插件的程序类。
- Groovy 插件的程序:
package com.github.fairy.era.plugins
import org.gradle.api.Plugin
import org.gradle.api.Project
class CustomPlugin implements Plugin<Project> {
@Override
void apply(Project project) {
project.extensions.create('param', ParamExtension) // 参数的配置
project.task('message', group: 'com.github.fairy.era') {
doLast {
println '【固定输出】你好啊,Groovy'
println '【动态输出】你好啊,Groovy' + project.param.info
}
}
}
}
class ParamExtension { // 参数的扩充
String info
}
2.4 插件引用
- 修改 build.gradle 配置文件,进行插件的引用:
import com.github.fairy.era.plugins.CustomPlugin // 导入程序组件
apply plugin: CustomPlugin // 插件引入
param {
info 'Gradle 香吗?'
}
2.5 执行任务
- 程序执行命令:
gradle message
- 程序执行结果:
14:30:14: 正在执行 'message'…
> Task :buildSrc:compileJava NO-SOURCE
> Task :buildSrc:compileGroovy UP-TO-DATE
> Task :buildSrc:processResources NO-SOURCE
> Task :buildSrc:classes UP-TO-DATE
> Task :buildSrc:jar UP-TO-DATE
> Task :buildSrc:assemble UP-TO-DATE
> Task :buildSrc:compileTestJava NO-SOURCE
> Task :buildSrc:compileTestGroovy NO-SOURCE
> Task :buildSrc:processTestResources NO-SOURCE
> Task :buildSrc:testClasses UP-TO-DATE
> Task :buildSrc:test NO-SOURCE
> Task :buildSrc:check UP-TO-DATE
> Task :buildSrc:build UP-TO-DATE
> Task :message
【固定输出】你好啊,Groovy
【动态输出】你好啊,GroovyGradle 香吗?
BUILD SUCCESSFUL in 424ms
1 actionable task: 1 executed
14:30:15: 执行完成 'message'。
- 此时就可以直接将插件定义在特定的目录之中,同时使用 Groovy 程序类进行插件的具体编写,那么也可以发现传入了相关的配置参数。
第三章:配置 Gradle 插件 ID
3.1 概述
虽然现在已经开发出了一系列的插件,但是会觉得此时所编写的插件和之前使用的第三方的插件有所不同。
第三方的插件导入:
plugins {
id 'java' // 配置的是一个 Java 插件(Java 项目)
id 'java-library'
}
我们的插件导入:
import com.github.fairy.era.plugins.CustomPlugin // 导入程序组件
apply plugin: CustomPlugin // 插件引入
所以如果想让我们自己的插件和第三方的插件一样使用,就需要为插件定义有相关的 ID 信息,但是这样就需要对插件进行配置。
3.2 创建 resources 目录
- 在之前进行插件定义的时候只创建了一个 src/main/groovy 的程序目录,本次还需要在同样的目录层级下创建有一个 resources 的目录。
3.3 META-INF
- 在 src/main/resources 目录下创建一个 META-INF 的目录。
3.4 gradle-plugins
- 在 src/main/resources/META-INF 目录中创建一个
gradle-plugins
的目录。
3.5 定义插件的 ID
- 每一个 properties 文件就属于插件 ID , 本次创建一个 fairy.properties 的属性文件,内容如下:
implementation-class=com.github.fairy.era.plugins.CustomPlugin
3.6 Gradle 配置
- 既然此时已经为插件提供了 ID ,那么就可以在 build.gradle 配置文件中直接进行 ID 的引用:
plugins {
id 'java' // 配置的是一个 Java 插件(Java 项目)
id 'java-library'
id 'fairy'
}
param {
info 'Gradle 香吗?'
}
3.7 执行任务
- 通过 ID 已经成功的实现了插件的引用,随后在项目中执行插件定义的任务。
- 程序执行命令:
gradle message
- 程序执行结果:
14:53:39: 正在执行 'message'…
> Task :buildSrc:compileJava NO-SOURCE
> Task :buildSrc:compileGroovy UP-TO-DATE
> Task :buildSrc:processResources UP-TO-DATE
> Task :buildSrc:classes UP-TO-DATE
> Task :buildSrc:jar UP-TO-DATE
> Task :buildSrc:assemble UP-TO-DATE
> Task :buildSrc:compileTestJava NO-SOURCE
> Task :buildSrc:compileTestGroovy NO-SOURCE
> Task :buildSrc:processTestResources NO-SOURCE
> Task :buildSrc:testClasses UP-TO-DATE
> Task :buildSrc:test NO-SOURCE
> Task :buildSrc:check UP-TO-DATE
> Task :buildSrc:build UP-TO-DATE
> Task :message
【固定输出】你好啊,Groovy
【动态输出】你好啊,GroovyGradle 香吗?
BUILD SUCCESSFUL in 118ms
1 actionable task: 1 executed
14:53:39: 执行完成 'message'。
- 那么此时就感觉到我们个人所开发的插件就可以像第三方插件一样进行有效的追加和配置,那么以后就可以将一些自己定义的任务放在插件中进行统一的管理。
第四章:创建 Gradle 插件项目
4.1 概述
- 之前所创建的插件都是在一个项目中完成的,但是在实际开发中,肯定希望插件开发完毕后,可以供所有的开发者直接使用,那么此时就需要创建有一个单独的项目,同时基于 nexus 私服实现插件的管理(当然,你也可以申请发布到中央仓库中)。
4.2 插件项目
- 创建 Groovy 类型的 Gradle 项目。
4.3 项目结构
- 此时所创建的项目由于是一个 Groovy 类型的项目,所以这个项目内部所创建的源代码的目录的名称也会自动匹配。
4.4 依赖配置
- 如果要想进行插件的开发,那么必须修改项目中的依赖,修改 build.gradle 文件:
plugins {
id 'groovy' // groovy 插件
id 'java' // java 插件
id 'maven-publish' // maven 插件
}
group 'com.github.fairy.era'
version '1.0'
repositories {
mavenCentral()
}
dependencies {
implementation 'org.codehaus.groovy:groovy-all:3.0.9'
implementation gradleApi()
implementation localGroovy()
testImplementation 'org.junit.jupiter:junit-jupiter:5.8.2'
}
test {
useJUnitPlatform()
}
- 此时项目中配置的 groovy-all 依赖库的版本需要和本地系统中的 groovy 的版本保持一致。
4.5 打包和上传配置
- 整个的插件项目最终一定要发布到 nexus 私服之中,所以一定要有打包的配置,打包就需要有编码的设置,同时也需要定义上传的任务配置。
- 修改 build.gradle 配置文件,进行打包配置:
// 打包配置
task sourceJar(type: Jar, dependsOn: classes) {
archiveClassifier.set 'sources'
from sourceSets.main.allSource
}
tasks.withType(JavaCompile) { // 针对程序编译的任务进行配置
options.encoding = "UTF-8"
}
artifacts { // 最终的打包操作任务
archives sourceJar
}
- 修改 build.gradle 配置文件,进行打包名称的配置:
archivesBaseName = 'fairy' // 打包名称尽量和插件名称相同
- 修改 build.gradle 配置文件,进行上传任务配置:
publishing {
publications {
maven(MavenPublication) {
// 如果是war包填写components.web,如果是jar包填写components.java
from components.java
groupId = project.group
artifactId = project.name
version = project.version
}
}
repositories {
maven {
allowInsecureProtocol = true
// 指定要上传的maven私服仓库
url = version.endsWith('SNAPSHOT') ? "http://192.168.65.100/repository/erp-snapshot/" : "http://192.168.65.100/repository/erp-release/"
//认证用户和密码
credentials {
username 'zhangsan'
password '123456'
}
}
}
}
4.6 代码配置
- 通过之前的程序拷贝相应的插件代码:
package com.github.fairy.era.plugins
import org.gradle.api.Plugin
import org.gradle.api.Project
class CustomPlugin implements Plugin<Project> {
@Override
void apply(Project project) {
project.extensions.create('param', ParamExtension) // 参数的配置
project.task('message', group: 'com.github.fairy.era') {
doLast {
println '【固定输出】你好啊,Groovy'
println '【动态输出】你好啊,Groovy' + project.param.info
}
}
}
}
class ParamExtension { // 参数的扩充
String info
}
4.7 插件 ID 配置
- 本次创建一个 fairy 的 ID ,也是拷贝之前的配置,内容如下:
implementation-class=com.github.fairy.era.plugins.CustomPlugin
4.8 新建 gradle.properties
- 新建 gradle.properties 文件,主要为了防止
Cannot upload checksum for module-maven-metadata.xml
错误,内容如下:
systemProp.org.gradle.internal.publish.checksums.insecure=true
4.9 组件发布
- 当组件配置成功之后,就可以进行该插件的发布,直接打包处理。
- 程序执行命令:
gradle publish
- 程序执行结果:
4.10 插件的引入
- 现在在其他项目中进行相关插件的引入,修改引入该插件项目的 build.gradle 文件:
plugins {
id 'java' // 配置的是一个Java插件(Java项目)
id 'idea'
id 'fairy'
}
repositories { // 仓库配置
maven {
allowInsecureProtocol= true
url 'http://192.168.65.100/repository/maven-public/'
}
maven {
url 'https://maven.aliyun.com/repository/public'
}
mavenCentral()
}
param {
info = 'Gradle 香吗?'
}
- 但是,此时出现了如下的错误信息:
Build file 'D:\project\gradle-02\build.gradle' line: 8
Plugin [id: 'era'] was not found in any of the following sources:
* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output. Run with --scan to get full insights.
4.11 定义全局仓库
- 在 plugins 配置之前去定义一个 buildscript ,修改 build.gradle 文件:
buildscript {
repositories { // 仓库配置
maven {
allowInsecureProtocol= true
url 'http://192.168.65.100/repository/maven-public/'
}
maven {
url 'https://maven.aliyun.com/repository/public'
}
mavenCentral()
}
dependencies{ // 设置项目的依赖
classpath 'com.github.fairy.era:fairy:1.0'
}
}
- 但是,此时出现了如下的错误信息:
Build file 'D:\project\gradle-02\build.gradle' line: 24
Plugin [id: 'era'] was not found in any of the following sources:
* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output. Run with --scan to get full insights.
4.12 插件引入
- 既然直接在 plugins 中的配置无法生效,那么可以考虑使用 apply 语法形式进行插件的引入,修改 build.gradle 文件:
plugins {
id 'java' // 配置的是一个Java插件(Java项目)
id 'idea'
}
apply plugin: 'fairy'
- 本次更换了一种插件引入的形式(无赖之举,因为按照传统的方式,通过 plugins 可以导入指定的插件)。
4.13 任务执行
- 此时,该项目中成功引入了插件之后,也有了对应的任务了。
- 程序执行命令:
gradle message
- 程序执行结果:
16:21:02: 正在执行 'message'…
> Task :message
【固定输出】你好啊,Groovy
【动态输出】你好啊,GroovyGradle 香吗?
BUILD SUCCESSFUL in 202ms
1 actionable task: 1 executed
16:21:02: 执行完成 'message'。