gradle打包spring boot的测试、正式war、jar包

1、前言

  项目使用spring boot编写使用yaml编写sping boot的配置。同时使用profiles的active这个配置选项激活不同的配置文件,达到区分测试和生产环境配置的目的,其中环境的配置文件格式是这样的:application-xxx.yml,其中xxx是具体要激活的配置。具体的application.yml负责加载不同配置,application具体代码如下:

spring:
  profiles:
    active: dev

logging:
  config: classpath:logback-spring.xml

  其中的问题就是每次打包都要改动application.yml的active选项,很不方便,有时打包还会忘记改动配置。所以就有编写一个gradle打包测试和正式环境的war包的需求。
  基本思路是重写bootWar脚本,再者观察到是一些列的操作再到bootWar操作的,而且gradle的task是有前置和后置方法的,所以在前置方法中通过文件读写改变application.yml的active的值,再执行bootWar操作即可完成目标war的生成。

2、系统环境

jdk版本:1.8
gradle版本:v5.1

3、BootWar脚本

编写独立的task.gradle

buildscript {
    ext {
        springBootVersion = '2.0.2.RELEASE'
        //启动类名称
        startClass = 'OperationDecisionApplication'
    }
    repositories {
        mavenCentral()
    }
    dependencies {
        classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
    }
}

task bootDevWar(type: org.springframework.boot.gradle.tasks.bundling.BootWar) {
    def env = "dev"
    doFirst {
        def file = new File("${buildDir}/resources/main/application.yml")
        println("正在编译war包---环境[${env}]")
        println("${buildDir}")
        def profile = ""
        file.eachLine { line ->
            if (line.endsWith("prod") && !(line = line.replace("prod", "dev")) == ("")) {}
            profile += line + "\r\n"
        }
        println(profile)
        file.newWriter(false).with {
            it.write(profile)
            it.flush()
            it.close()
        }
    }
    group 'build War'
    description 'pack a dev war'
    mainClassName = "com.XXX.${startClass}"//启动类
    destinationDir = file("build/libs/${env}")
}

task bootProdWar(type: org.springframework.boot.gradle.tasks.bundling.BootWar) {
    def env = "prod"
    doFirst {
        def file = new File("${buildDir}/resources/main/application.yml")
        println("正在编译war包---环境[${env}]")
        println("${buildDir}")
        def profile = ""
        file.eachLine { line ->
            if (line.endsWith("dev") && !(line = line.replace("dev", "prod")) == ("")) {}
            profile += line + "\r\n"
        }
        println(profile)
        file.newWriter(false).with {
            it.write(profile)
            it.flush()
            it.close()
        }
    }
    group 'build War'
    description 'pack a dev war'
    mainClassName = "com.XXX.${startClass}"//启动类
    destinationDir = file("build/libs/${env}")
}

下面解释一下,一些知识点:

  • buildscript引入构建gradle文件自解析文档结构的能力,让 build.gradle能够引入这个task.gradle。
  • type: org.springframework.boot.gradle.tasks.bundling.BootWar是继承语法,继承自org.springframework.boot.gradle.tasks.bundling.BootWar,这个全路径类
  • 需要引入spring-boot-gradle-plugin,来支持bootWar脚本,classpath(“org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}”)
  • doFirst方法是task接口实现类的前置方法,在具体方法执行之前执行
  • group 'build War’将gradle的task任务分组显示
  • mainClassName是Spring Boot的启动Application类,不配置这个war包是启动不了的
  • destinationDir是War文件的输出路径
    这是分组的效果:
    在这里插入图片描述
    在build.gradle中用apply from:“task.gradle”,引入写的gradle,如果觉得这样子不好,也可以直接在build.gradle中写task。
    文件路径如下:
    在这里插入图片描述

4、BootJar脚本

note: 因为差不多内容,所以把BootJar的脚本补在这里
项目使用的是application.properties,所以占位符跟yaml的差不多。效果如下:
在这里插入图片描述
基本思路是,通过finalizedBy关键字设置后置执行bootJar,在执行前,当前Task任务变更build/libs下的application.properties的内容,同时更改bootJar输出路径。
脚本如下:

buildscript {
    ext {
        springBootVersion = '2.1.4.RELEASE'
        //启动类名称
        projStartClass = 'EcApplication'
    }
    repositories {
        mavenCentral()
    }
    dependencies {
        classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
    }
}

task bootDevJar() {
    def env = "dev"
    doFirst {
        bootJar.destinationDir = file("build/libs/${env}")
        def file = new File("${buildDir}/resources/main/application.properties")
        println("正在编译war包---环境[${env}]")
        println("${buildDir}")
        def profile = ""
        file.eachLine { line ->
            if (line.endsWith("prod") && !(line = line.replace("prod", "dev")) == ("")) {
            }
            profile += line + "\r\n"
        }
        println(profile)
        file.newWriter(false).with {
            it.write(profile)
            it.flush()
            it.close()
        }
    }
    group 'build Jar'
    description 'pack a dev jar'
    dependsOn("compileJava", "processResources", "classes")
}

bootDevJar.finalizedBy bootJar

task bootProdJar() {
    def env = "prod"
    doFirst {
        bootJar.destinationDir = file("build/libs/${env}")
        def file = new File("${buildDir}/resources/main/application.properties")
        println("正在编译war包---环境[${env}]")
        println("${buildDir}")
        def profile = ""
        file.eachLine { line ->
            if (line.endsWith("dev") && !(line = line.replace("dev", "prod")) == ("")) {
            }
            profile += line + "\r\n"
        }
        println(profile)
        file.newWriter(false).with {
            it.write(profile)
            it.flush()
            it.close()
        }
    }
    group 'build Jar'
    description 'pack a dev jar'
    dependsOn("compileJava", "processResources", "classes")
}

bootProdJar.finalizedBy bootJar

bootJar {
    doLast {//清除变量
        bootJar.destinationDir = file("build/libs")
    }
}

这次实现没有采用继承的方式,而是用采用执行链中更改前置task更改后置task的方式变量实现。不采用继承的主要原因是BOOT-INF文件夹下东西没有打包进jar包,就我个人观察而言,是BootJar的构造方法不执行。
这个关系关系链如下:compileJava -> processResources -> classes - > bootProdJar/bootDevJar -> bootJar
分三步走:

  • 在compileJava -> processResources -> classes中生成打包相关临时文件
  • bootProdJar/bootDevJar中更改临时文件application.properties达到更改配置文件-
  • bootJar使用前面生成和处理的临时文件打包

dependsOn(“compileJava”, “processResources”, “classes”)是设置前置task链,bootProdJar.finalizedBy bootJar
是设置后置任务bootJar

bootProdJar/bootDevJar的doFirst中通过bootJar.destinationDir = file(“build/libs/${env}”)更改bootJar文件的输出路径
在bootJar的doLast将变量置回默认,防止影响默认的bootJar命令。

在build.gradle中用apply from:“task.gradle”,引入写的gradle,如果觉得这样子不好,也可以直接在build.gradle中写task。
文件路径如下:
在这里插入图片描述

5、ssh的put脚本

因为代码写在task.gradle文件,所以在build.gradle中写添加ssh插件:
在这里插入图片描述
在apply from:"task.gradle"上一行填入apply plugin: ‘org.hidetake.ssh’,引入gradle的ssh插件。

为org.hidetake.ssh插件内置变量赋值:

//远程服务器信息
remotes {
    devService {
        host = '106.12.128.166'
        user = 'root'
        password = 'passwd'
        knownHosts = allowAnyHosts//加了这个才能ssh上传文件
    }
    prodService {
        host = '134.175.85.159'
        user = 'ubuntu'
        password = 'passwd'
        retryCount = 1 //重连次数,0为取消重新
        retryWaitSec = 3
        knownHosts = allowAnyHosts
    }
}

在这里插入图片描述
war包的具体逻辑:

task putWar {
    group 'build War'
    description 'put war to service and execute'

    doLast {
        if (!project.hasProperty('isRelease')) {
            println "没有设置env变量,任务停止"
            return
        }
        def env = project.getProperties().get("isRelease")=="true"?"prod":"dev"
        println "put war pack to " + project.getProperties().get("env") + " service"
        if (env == "dev") {
            project.ssh.run {
                session(project.remotes.DevService) {
                    put from: "${buildDir}/libs/${env}/decision-external.war", into: "${tomcatRootDic}/webapps/"
                    execute "${tomcatRootDic}/bin/tomcat-restart.sh"
                }
            }
            println "put war pack to ${env} service ${project.remotes.DevService.host}"
        } else if (env == "prod") {
            project.ssh.run {
                session(project.remotes.DevService) {
                    put from: "${buildDir}/libs/${env}/decision-external.war", into: "${tomcatRootDic}/webapps/"
                    execute "${tomcatRootDic}/bin/tomcat-restart.sh"
                }
            }
            println "put war pack to ${env} service ${project.remotes.DevService.host}"
        }
    }
}

jar包的具体逻辑:

task putJar() {
    group 'build Jar'
    description 'put jar to service and execute'

    doLast {
        if (!project.hasProperty('isRelease')) {
            println "没有设置env变量,任务停止"
            return
        }
        def env = project.getProperties().get("isRelease")=="true"?"prod":"dev"
        println "put jar pack to ${env} service"
        if (env == "dev") {
            project.ssh.run {
                session(project.remotes.devService) {
                    put from: "${buildDir}/libs/${env}/ec-1.0.jar", into: "/data/"
                    execute "/data/restart-jar.sh"
                }
            }
            println "put jar pack to ${env} service ${project.remotes.devService.host}"
        } else if (env == "prod") {
            project.ssh.run {
                session(project.remotes.prodService) {
                    put from: "${buildDir}/libs/${env}/ec-1.0.jar", into: "/data/"
                    execute "/data/restart-jar.sh"
                }
            }
            println "put jar pack to ${env} service ${project.remotes.prodService.host}"
        }
    }
}

这里具体要执行的东西,仅供参考,因为这是两个项目的put方法的实现,稍微修改一下即可。

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值