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

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