第一章 企业级 gradle 依赖管理层次结构设计
Gradle概述
Gradle是一个基于Apache Ant和Apache Maven概念的项目自动化构建工具。它使用一种基于Groovy的特定领域语言来声明项目设置,而不是传统的XML。Gradle就是工程的管理,帮我们做了依赖、打包、部署、发布、各种渠道的差异管理等工作。
Gradle优势
- 一款最新的,功能最强大的构建工具,用它逼格更高
- 使用程序代替传统的XML配置,项目构建更灵活
- 丰富的第三方插件,让你随心所欲使用
- Maven、Ant能做的,Gradle都能做,但是Gradle能做的,Maven、Ant不一定能做。
Maven中依赖概述
- 一方库:本工程中各个模块之间的依赖
- 二方库(xxx-dependencies):企业内部的依赖库,一般指企业内部的其他项目发布的依赖(jar 包)
- 三方库(xxx-parent):企业之外的第三方依赖库, 如 Spring、Apache、Google 等发布的依赖(jar 包)
一般来说,企业的开发框架搭建完成后,三方库依赖除了漏洞和 Bug 升级外,很少频繁升级大改,而企业内部的二方库由于迭代和更新,版本升级频率较三方库要高,所以层次结构中二方库依赖三方库,三方库在更底层。先控制三方库依赖版本,在此基础上再控制二方库的版本。这里只对项目结构设计进行讲解,至于Nexus 私服搭建大家百度一下就好了。
项目搭建
本文项目地址 jingwei-cloud
新建项目初始化工程
**sparrow **模块为 **jingwei-cloud **的两方库模块,**jingwei-cloud **所有子模块均会引入该模块,这个模块相当于企业中的共享模块,后期也可以单独拆分成一个独立工程维护。
- sparrow目录结构
jingwei-cloud配置
- jingwei-cloud > build.gradle
buildscript {
ext {
set("springBootVersion", "2.3.4.RELEASE")
set("dependencyManagementVersion", "1.0.10.RELEASE")
}
}
description = "根目录用于管理所有项目"
configurations.all {
resolutionStrategy.cacheChangingModulesFor 0, 'seconds'
}
allprojects {
repositories {
maven { url 'https://maven.aliyun.com/repository/public/' }
mavenCentral()
}
tasks.withType(JavaCompile) {
options.encoding = "UTF-8"
}
}
sparrow根模块
- jingwei-cloud > sparrow > build.gradle
import org.springframework.boot.gradle.plugin.SpringBootPlugin
buildscript {
ext {
set("ignoreProjects",
[
project(":sparrow:sparrow-parent"),
project(":sparrow:sparrow-dependencies"),
]
)
set("moduleProjects", subprojects - ignoreProjects)
// 两方包 不能包含引用jar
set("excludeProjects", project(":sparrow:sparrow-client"))
}
}
plugins {
id 'org.springframework.boot' version "$springBootVersion" apply false
id 'io.spring.dependency-management' version "$dependencyManagementVersion" apply false
id 'java'
}
description = "sparrow(麻雀), 基础工程,通用工程骨架"
allprojects {
group = 'com.vastmoon.sparrow'
version = '2.0.0-SNAPSHOT'
}
configure(moduleProjects) {
apply plugin: "java"
apply from: "${rootDir}/gradle/framework-module.gradle"
sourceCompatibility = '1.8'
configurations {
compileOnly {
extendsFrom annotationProcessor
}
}
test {
useJUnitPlatform()
}
}
configure(moduleProjects - excludeProjects) {
apply plugin: "io.spring.dependency-management"
dependencyManagement {
imports {
mavenBom SpringBootPlugin.BOM_COORDINATES
}
generatedPomCustomization {
enabled = false
}
}
dependencies {
implementation(enforcedPlatform(project(":sparrow:sparrow-parent")))
annotationProcessor 'org.projectlombok:lombok'
compileOnly 'org.projectlombok:lombok'
annotationProcessor 'org.springframework.boot:spring-boot-configuration-processor'
testImplementation('org.springframework.boot:spring-boot-starter-test') {
exclude group: 'org.junit.vintage', module: 'junit-vintage-engine'
}
implementation("org.springframework.boot:spring-boot-starter-validation")
implementation("org.apache.commons:commons-collections4")
implementation("cn.hutool:hutool-all")
implementation("org.apache.commons:commons-lang3")
implementation("com.google.guava:guava")
}
}
set("excludeProjects", project(":sparrow:sparrow-client"))
client不能包含任何依赖,这个包可能会发给Dubbo等RPC框架实现远程调用,因此不能依赖第三方jar包
apply plugin: "io.spring.dependency-management"
dependencyManagement {
imports {
mavenBom SpringBootPlugin.BOM_COORDINATES
}
generatedPomCustomization {
enabled = false
}
}
这里有一个坑,如果不这样配置,会找不到spingboot的依赖,目前没有找到什么原因造成的。具体错误原因如下图:![1-gradle报错.jpeg](https://img-blog.csdnimg.cn/img_convert/75b4fb8898e1ce6a07858aec66c3b785.png#align=left&display=inline&height=736&margin=[object Object]&name=1-gradle报错.jpeg&originHeight=736&originWidth=1366&size=228996&status=done&style=none&width=1366)
sparrow-parent 配置
- jingwei-cloud > sparrow > sparrow-parent > build.gradle
import org.springframework.boot.gradle.plugin.SpringBootPlugin
apply plugin: 'java-platform'
apply from: "$rootDir/gradle/publications.gradle"
ext {
set('springCloudAlibabaVersion', "2.2.2.RELEASE")
set('springCloudVersion', "Hoxton.SR8")
set("collections4Version", "4.4")
set("hutoolVersion", "5.4.7")
set("ulisesbocchioVersion", "3.0.3")
set("springSecurityJwtVersion", "1.1.1.RELEASE")
}
javaPlatform {
allowDependencies()
}
dependencies {
api enforcedPlatform(SpringBootPlugin.BOM_COORDINATES)
api enforcedPlatform("org.springframework.cloud:spring-cloud-dependencies:${springCloudVersion}")
api enforcedPlatform("com.alibaba.cloud:spring-cloud-alibaba-dependencies:${springCloudAlibabaVersion}")
constraints {
api("org.apache.commons:commons-collections4:$collections4Version")
api("cn.hutool:hutool-all:$hutoolVersion")
api("com.github.ulisesbocchio:jasypt-spring-boot:$ulisesbocchioVersion")
api('org.springframework.security:spring-security-jwt:$springSecurityJwtVersion')
}
}
publishing {
publications {
//noinspection GroovyAssignabilityCheck
mavenJava(MavenPublication) {
//noinspection GroovyAssignabilityCheck
from components.javaPlatform
}
}
}
sparrow-parent 模块为三方库管理模块,主要用于维护三方库, 这里用到的插件 java-platform
具体的配置信息大家可以去官网查看,官网地址 :https://docs.gradle.org/current/userguide/java_platform_plugin.html
sparrow-dependencies配置
- jingwei-cloud > sparrow > sparrow-dependencies > build.gradle
apply plugin: 'java-platform'
apply from: "$rootDir/gradle/publications.gradle"
javaPlatform {
allowDependencies()
}
dependencies {
api enforcedPlatform(project(":sparrow:sparrow-parent"))
constraints {
parent.moduleProjects.sort { it.name }.each {
api it
}
}
}
publishing {
publications {
//noinspection GroovyAssignabilityCheck
mavenJava(MavenPublication) {
//noinspection GroovyAssignabilityCheck
from components.javaPlatform
}
}
}
sparrow-dependencies 模块为两方库模块,下面的配置为把两方模块加入到pom文件中
constraints {
parent.moduleProjects.sort { it.name }.each {
api it
}
}
项目编译
sparrow-parent pom文件
- sparrow > sparrow-parent > build > publications > mavenJava > pom-default.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<!-- This module was also published with a richer model, Gradle metadata, -->
<!-- which should be used instead. Do not delete the following line which -->
<!-- is to indicate to Gradle or any Gradle module metadata file consumer -->
<!-- that they should prefer consuming it instead. -->
<!-- do_not_remove: published-with-gradle-metadata -->
<modelVersion>4.0.0</modelVersion>
<groupId>com.vastmoon.sparrow</groupId>
<artifactId>sparrow-parent</artifactId>
<version>2.0.0-SNAPSHOT</version>
<packaging>pom</packaging>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-collections4</artifactId>
<version>4.4</version>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.4.7</version>
</dependency>
<dependency>
<groupId>com.github.ulisesbocchio</groupId>
<artifactId>jasypt-spring-boot</artifactId>
<version>3.0.3</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-jwt</artifactId>
<version>$springSecurityJwtVersion</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>2.3.4.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Hoxton.SR8</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>2.2.2.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
</project>
sparrow-dependencies pom文件
- sparrow > sparrow-dependencies > build > publications > mavenJava > pom-default.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<!-- This module was also published with a richer model, Gradle metadata, -->
<!-- which should be used instead. Do not delete the following line which -->
<!-- is to indicate to Gradle or any Gradle module metadata file consumer -->
<!-- that they should prefer consuming it instead. -->
<!-- do_not_remove: published-with-gradle-metadata -->
<modelVersion>4.0.0</modelVersion>
<groupId>com.vastmoon.sparrow</groupId>
<artifactId>sparrow-dependencies</artifactId>
<version>2.0.0-SNAPSHOT</version>
<packaging>pom</packaging>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.vastmoon.sparrow</groupId>
<artifactId>sparrow-client</artifactId>
<version>2.0.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>com.vastmoon.sparrow</groupId>
<artifactId>sparrow-core</artifactId>
<version>2.0.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>com.vastmoon.sparrow</groupId>
<artifactId>sparrow-parent</artifactId>
<version>2.0.0-SNAPSHOT</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
</project>
上传私服公共配置
这里参照了spring-framework的公共配置
- gradle > framework-module.gradle
apply from: "$rootDir/gradle/publications.gradle"
jar {
manifest.attributes["Implementation-Title"] = project.name
manifest.attributes["Implementation-Version"] = project.version
manifest.attributes["Automatic-Module-Name"] = project.name.replace('-', '.') // for Jigsaw
manifest.attributes["Created-By"] =
"${System.getProperty("java.version")} (${System.getProperty("java.specification.vendor")})"
// from("${rootDir}/src/docs/dist") {
// include "license.txt"
// include "notice.txt"
// into "META-INF"
// expand(copyright: new Date().format("yyyy"), version: project.version)
// }
}
publishing {
publications {
mavenJava(MavenPublication) {
from components.java
// artifact sourcesJar
// artifact javadocJar
}
}
}
- gradle > publications.gradle
apply plugin: "maven-publish"
publishing {
publications {
mavenJava(MavenPublication) {
pom {
afterEvaluate {
name = project.description
description = project.description
}
}
versionMapping {
usage('java-api') {
fromResolutionResult()
}
usage('java-runtime') {
fromResolutionResult()
}
}
}
}
repositories {
maven {
// change to point to your repo, e.g. http://my.org/repo
def releasesRepoUrl = "http://localhost:8081/repository/maven-releases/"
def snapshotsRepoUrl = "http://localhost:8081/repository/maven-snapshots/"
url = version.endsWith('SNAPSHOT') ? snapshotsRepoUrl : releasesRepoUrl
credentials {
username = 'admin'
password = 'admin123'
}
}
}
}
可选模块
这里还创建了一个sparrow-gradle-plugin
模块用于公司内部统一使用springboot版本
sparrow-gradle-plugin build.gradle
- sparrow > sparrow-gradle-plugin > build.gradle
plugins {
id "java-gradle-plugin"
}
apply from: "$rootDir/gradle/publications.gradle"
dependencies {
implementation "org.springframework.boot:spring-boot-gradle-plugin:$springBootVersion"
implementation "io.spring.gradle:dependency-management-plugin:$dependencyManagementVersion"
}
gradlePlugin {
plugins {
sparrowGradlePlugin {
//noinspection GroovyAssignabilityCheck
id = 'com.vastmoon.sparrow'
//noinspection GroovyAssignabilityCheck
implementationClass = 'com.vastmoon.sparrow.gradle.SparrowGradlePlugin'
}
}
}
sparrow-gradle-plugin 插件类
public class SparrowGradlePlugin implements Plugin<Project> {
public static final String BOM_COORDINATES = "com.vastmoon.sparrow:sparrow-dependencies:";
@Override
public void apply(Project project) {
project.getPlugins().apply(SpringBootPlugin.class);
}
}
引用sparrow到其他工程中
新建一个新项目 sparrow-example
- sparrow-example > settings.gradle
pluginManagement {
repositories {
gradlePluginPortal()
maven { url 'https://maven.aliyun.com/repository/public/' }
mavenCentral()
mavenLocal()
maven { url 'http://localhost:8081/repository/maven-public/' }
}
}
rootProject.name = 'sparrow-example'
- sparrow-example > build.gradle
buildscript {
ext {
set("sparrowVersion", "2.0.0-SNAPSHOT")
}
}
plugins {
id 'com.vastmoon.sparrow' version "$sparrowVersion" apply false
id 'java'
}
description = "sparrow测试项目"
group = 'com.vastmoon.example'
version = '0.0.1-SNAPSHOT'
repositories {
mavenLocal()
maven { url 'https://maven.aliyun.com/repository/public/' }
mavenCentral()
maven { url 'http://localhost:8081/repository/maven-public/' }
}
configurations {
compileOnly {
extendsFrom annotationProcessor
}
}
test {
useJUnitPlatform()
}
apply plugin: "io.spring.dependency-management"
dependencyManagement {
imports {
mavenBom "com.vastmoon.sparrow:sparrow-dependencies:$sparrowVersion"
}
}
apply plugin: "org.springframework.boot"
dependencies {
implementation("com.vastmoon.sparrow:sparrow-core")
annotationProcessor 'org.projectlombok:lombok'
compileOnly 'org.projectlombok:lombok'
implementation("org.springframework.boot:spring-boot-starter-web")
annotationProcessor 'org.springframework.boot:spring-boot-configuration-processor'
testImplementation('org.springframework.boot:spring-boot-starter-test') {
exclude group: 'org.junit.vintage', module: 'junit-vintage-engine'
}
}
总结
这样的结构我参照着springboot源码和spring-framework源码的工程目录总结出来的,现在看来和maven的项目管理没什么区别了,希望gradle构建多模块项目越来越方便。