我们在使用gradle的过程中,多少都会有个疑问,就是插件的写法与依赖的写法为什么不太一样?
插件的写法:

plugins {
    java
    id("org.springframework.boot") version "3.5.7"
    id("io.spring.dependency-management") version "1.1.7"
}

依赖的写法:

dependencies {
    implementation("org.springframework.boot:spring-boot-starter-data-jpa")
}

其中依赖的写法对应经典的maven依赖的三段定义方式,在有依赖管理的情况下,可以省略版本号。插件中java这种核心插件因为内置在gradle本身之中,可以简化处理也不奇怪。但spring boot这种三方插件的写法就跟依赖不太一样。

如果说插件跟依赖本来就是两种东西,存在不同的库中,gradle爱怎么管理都行。但实际上他们又都可以存在maven仓库中。开发时只能用公司私服不能连外网的朋友肯定深有体会,插件和依赖其实都是在一个仓里的。

既然如此,我们就要问了,gradle插件放在maven仓库里,写法有不按maven的三坐标来,那gradle是如何找到插件的呢?接下来我们就拆解一下gradle的寻插件之路。

gradle插件仓

gradle虽然不像maven有一个中央仓,但它专门为插件建了一个仓库:Gradle Plugin Portal,一个你可以用id找到插件的地方。
Gradle Plugin Portal
这里找插件非常方便,它会明确给出id和version,也会像maven中央仓一样给出示例代码。这里用id和version定位插件看上去很合理,正如上文所说,毕竟不是maven仓库,说不定gradle就新设计一套呢。但实际上并没有,这个仓库格式跟maven完全一样,后文会说明这一点。

maven中央仓

既然在Gradle Plugin Portal中用id和version定位插件看上去天经地义,那么我们就来看看我们有疑问的maven仓库吧,还是搜org.springframework.boot
在Maven Central Repository中搜org.springframework.boot
搜出的第一名,我们一看就知道,它必然就是我们像找的对象。我们点进去,把构建工具选成gradle,它会给出这样的代码:implementation(platform("org.springframework.boot:org.springframework.boot.gradle.plugin:4.1.0-M4"))。我们把这条代码加到项目中,下载依赖,就会看到,这个项目只有一个pom文件,其中也只有一个依赖

    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-gradle-plugin</artifactId>
      <version>4.1.0-M4</version>
    </dependency>

毫无疑问,这就是我们要找的插件的本体。至此我们就搞清楚了gradle用id和version在maven仓库中定位插件的过程。总结一下,就是:

  1. id + version转化为:"{id}:{id}.gradle.plugin:{version}",这就是经典的三段式maven坐标。
  2. 读取"{id}:{id}.gradle.plugin:{version}"中的pom文件,这里面的依赖就是插件本体。这个pom只是一个“快捷方式”,也被称为Marker POM。

验证

我们拿io.spring.dependency-management验证一下。
io.spring.dependency-management
完全印证了上述结论。

如何开发

Spring开发团队难道要为了搞个gradle插件,打两个包?如果真是这样,也太反人类了。事实上,gradle为开发插件提供了相应的插件,只要执行publish的task,就可以一炮双响。可以参考gradle关于发布插件的文档,以及id("org.springframework.boot")的源码。
Preparing to Publish Plugins
Publishing Plugins
spring-boot-gradle-plugin源码

Gradle Plugin Portal的真面目

前文提到Gradle Plugin Portal格式跟maven完全一样,如何能证明这一点呢?只需要进入任何一个插件的详情页,展开下部的see also,就会发现我们所言非虚。
在这里插入图片描述

为何如此设计

相信很多朋友了解了gradle这套设计之后,都会有个疑问,通过一个“快捷方式”转一下,多请求这一下,不是多此一举吗?实际上我认为这是gradle设计者的巧思,不但不是多此一举,并且很可能是设计者引以为豪的设计之一。它的好处我觉得有如下几点:

  1. 优雅,本身gradle用了Groovy和Kotlin就比xml优雅了几个数量级,id+version的DSL比三段式又更优雅。
  2. 复用,直接复用maven成熟的仓库,既免去设计仓库的工作,又不用从零开始构建生态。
  3. 区分,依赖的类库,gradle还是用三段式,一眼就能看出来跟maven的对应关系,因为不管是gradle还是maven,这些类库都是同一批,本质也都一样,而插件是构建工具,里面的代码是不能在项目代码里调的,与之对应的在maven的pom文件中,因为插件和依赖都是三段式,有时就会搞混。
  4. 解耦,一般情况下,id+version对应唯一的Marker POM,进一步对应唯一的jar包,但这个过程并不是不可改变的,gradle提供了干涉这个映射过程的API,但这其实只是理论上的情况,极少有人用。
Logo

欢迎加入 MCP 技术社区!与志同道合者携手前行,一同解锁 MCP 技术的无限可能!

更多推荐