Springboot+Gradle+Docker构建多模块项目

背景

原有Springboot基于Maven构建的多模块项目需要改为Gradle版的多模块项目,派我前去开荒.

阅读前:请先对gradle有一定了解,概念什么的我就不多说,直接进入主题!

首先,分享下maven转gradle,gradle转有互转的语法,可把pom.xml或build.gradle文件单独拉到一个文件下执行装换命令。

Maven转Gradle:

gradle init --type pom

Gradle装Maven:

在build.gradle中增加以下内容(group,version可自行更改,artifactId默认为目录名称)
apply plugin: 'java'
apply plugin: 'maven'

group = 'com.101tec'
version = '0.7-dev'
sourceCompatibility = 1.6
然后./gradle.build,成功后将在build\poms目录下生成的pom-default.xml文件,把它复制到根目录下,改名成pom.xml即可

好了后,便开始踩坑之旅了,途中参考了很多链接帮助,忘了一一记录下来,如发现有侵权的,请联系我,我加上转发处。

首先,模块管理会在settings.gradle里添加include,如:

rootProject.name = 'Main'
include 'sub1'
include 'sub2'

配置build.gradle构建文件,构建多模块项目的两种方式,一种是集中式的共享配置,一种是分散式的私有配置。
第一种是所有配置都配置在父模块目录下的build.gradle,简便快捷,不过我采用了第二种。
各个模块配置一个build.gradle。
首先,在父模块的build.gradle中配置公共的属性,如:

    allprojects {
        apply plugin: 'maven'
        group = 'com.demo'
        version = '2.0.0'
    }
    subprojects {
        apply plugin: 'java'
        sourceCompatibility = 1.8
        targetCompatibility = 1.8
    
        repositories {
            mavenLocal()
            maven { url "https://plugins.gradle.org/m2/" }
        }
    
    
        dependencies {
            testCompile group: 'junit', name: 'junit', version: '4.12'
        }
    }

接着各个模块之间配置自己的依赖包,首先我遇到第一个问题:

引入子模块时exclude失效

依赖子模块时,要排除子模块中的某个jar包,如:

compile(group: 'com.alibaba', name: 'dubbo', version:'2.5.7') {
        exclude(module: 'spring')
        exclude(module: 'log4j')
}

上面的语法,针对外部jar包倒是没问题,但是到了子模块上,就排除不掉了,经过一番折腾,原来是要用下面这种语法:

 compile(project(':project-impl')){
        exclude(module: 'project-mybatis')
        exclude(module: 'mysql-connector-java')
 }

真是汗,去除个包还有语法限制。
接着,本地没遇到什么大坑了,成功跑了起来。而后,我又来部署测试环境了,首先先用Docker打包成镜像:

Gradle Docker plugin推荐

  1. se.transmode.gradle:gradle-docker:1.2
    这里不详谈,有很多文章描述,可查看掘金上的一篇:

    https://juejin.im/post/5b27b7ac51882574c32c6588

  2. gradle.plugin.com.palantir.gradle.docker:gradle-docker:0.19.2
    我用的便是这个,首先将其引入

buildscript {
    ...
    repositories {
        maven {url  "https://plugins.gradle.org/m2/"}
    }
    dependencies {
        classpath('gradle.plugin.com.palantir.gradle.docker:gradle-docker:0.19.2')
    }
}
apply plugin: 'com.palantir.docker'
docker {
    dockerfile file('Dockerfile') //DockerFile路径
    name "${project.group}/${jar.baseName}:${jar.version}"
    files jar.archivePath
    buildArgs(['JAR_FILE': "${jar.archiveName}"])
}

简单介绍下上面docker{}里面的参数:
name是镜像名,可自己设置名
buildArgs是设置构建时的环境变量,使用${jar.archiveName}获取构建完的jar包,将其赋值给JAR_FILE变量,在Dockerfile那边便可引用,如:

FROM openjdk:8
MAINTAINER dashuai
WORKDIR /
ARG JAR_FILE
ADD ${JAR_FILE} app.jar
EXPOSE 8080
ENTRYPOINT ["java","-jar","app.jar"]

Docker打包SpringBoot多模块项目

引入Docker配置便完成了,接着来到测试服务器上构建镜像。
服务器是Ubuntu系统的,先导入项目,进入根目录。

  1. 构建项目

    gradle build

  2. 包下载完后,在打包镜像,切记在父模块目录下执行

    gradle subProject:docker
    image

看到构建成功,好开森。
结果docker-compose up一跑,竟然出现:

No main manifest attribute, in app.jar

gradle构建的jar包找不到main入口

这就气了,镜像都打好了,你跟我说找不到main,然后又只能乖乖的找解决方案:
刚开始,本来用:

apply plugin: 'application'
mainClassName='com.main'

是可以运行的,本地是可以运行的,接着我又在服务器上运行:

gradle subProject:run

也是可以运行的,那为什么会找不到main呢,接着我又google,加了下面的配置:

jar {
    manifest {
        attributes 'Main-Class': 'com.main'
        attributes 'Class-Path': 'subProject.jar'
    }
}

在构建镜像,在启动容器,诶,竟然启动了,好开森,结果,有出现类找不到了。我去,这不科学啊!难道包没导进去,我便打开/build/libs/subProject.jar,看到里面只有一些项目文件,并没有发现jar,我去,打包成镜像没jar怎么运行,这是一想肯定是打jar包方式有问题,又去google。最终,还是让我解决了(っ•̀ω•́)っ✎⁾⁾。
最终的build.gradle如下:

buildscript {
    repositories {
        maven {url  "https://plugins.gradle.org/m2/"}
    }
    dependencies {
        classpath("org.springframework.boot:spring-boot-gradle-plugin:2.0.1.RELEASE")
        classpath('gradle.plugin.com.palantir.gradle.docker:gradle-docker:0.19.2')
    }
}

apply plugin: 'com.palantir.docker'
apply plugin: 'application'
apply plugin: 'org.springframework.boot'

group='com'
version = '3.0.5'
mainClassName='com.main'

tasks.withType(JavaCompile) {
	options.encoding = 'UTF-8'
}
dependencies {
    compile group: 'org.springframework.data', name: 'spring-data-redis', version: '2.0.6.RELEASE'
    compile 'net.sourceforge.nekohtml:nekohtml:1.9.21'
    compile(group: 'com.alibaba', name: 'dubbo', version:'2.5.7') {
        exclude(module: 'spring')
        exclude(module: 'log4j')
    }
    //zkclinet自带zookeeper不过版本太低,自己设一个版本给他,另外两个包都得exclude才有效
    // log4j在gradle上不能去除,否则会去引起连接zookeeper超时
    compile(group: 'org.apache.zookeeper', name: 'zookeeper', version:'3.4.11') {
        exclude(module: 'slf4j-log4j12')
    }
    compile ('com.github.sgroschupf:zkclient:0.1'){
        exclude(module: 'slf4j-log4j12')
    }
}

docker {
    dockerfile file('Dockerfile') //DockerFile路径
    name "${project.group}/${jar.baseName}:${jar.version}"
    files jar.archivePath
    buildArgs(['JAR_FILE': "${jar.archiveName}"])
}

总结:网上的东西最多只能作为参考,发现问题的本质在于思考,多踩坑,以后才能避免被坑,这是我开发当中遇到的。假如对你有帮助,请留下您宝贵的点赞。

如果想尝试使用该插件的话,可参考构建镜像Demo,GitHub地址:
https://github.com/liaozihong/SpringBoot-Learning/tree/master/SpringBoot-Builder-Docker

参考链接:
https://segmentfault.com/a/1190000008422142

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章