栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 系统运维 > 运维 > Linux

Devops之Gradle SpringBoot构建打包工程jar、搭建jenkins自动发布

Linux 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Devops之Gradle SpringBoot构建打包工程jar、搭建jenkins自动发布

本文逐渐涉及当前敏捷开发中非常火的DevOps相关的技术,也就是自动化开发运维。整体偏向于环境搭建,整体学习路线为:

(1)SpringBoot+Gradle+Nexus远程仓库构建打包工程jar

(2)搭建jenkins环境并自动关联打包好的工程jar进行自动发布

(3)搭建docker容器环境学习软件运行环境的搭建

(4)搭建K8S环境进行使用学习

后面容器化相关的将后面文章记录,本文主要对前两点进行总结。

(一)SpringBoot+Gradle工程构建打包工程jar

我们知道使用SpringBoot可以很容易搭建一个简单的web运行环境,主要是运用了springboot为我们自动配置的一系列配置和tomcat容器环境。但是当一个SpringBoot工程代码编写完之后需要发布,就没办法用那一套进行线上发布了,就必须要将需要运行的工程资源进行有机整合之后,再打包出来才可以进行线上发布。一般来说对于项目的构建打包通用可以用Maven或Gradle,由于Maven的构建打包非常耗时,因此一般来说使用Gradle可以很快替代Maven进行快速打包构建。

下面将以实际样例,介绍怎么使用Gradle打包构建出一个可以直接运行的jar/war工程,当然需要一定的Gradle基础或实际项目使用经验,关于Gradle的基础知识可以查阅小编的其它文章gradle基础+Groovy描述笔记(一)_喜欢火影的木易杨的博客-CSDN博客

不多说,直接show the code...

首先:新建一个Gradle SpringBoot项目可以看到build.gradle文件,添加启动类、properties文件、common.gradle文件,整体工程结构大致如下(由于最近在接触SpringCloudNacos相关的东西所以工程集成了Nacos的相关依赖,该工程主要是作为一个注册在Nacos作为服务方的工程):

(1)NacosProviderApplication:如果最后打包出来的工程可以正常启动,那么会有一行====日志输出

package com.alibaba.nacos.example.spring.cloud;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;


@SpringBootApplication
@EnableDiscoveryClient
public class NacosProviderApplication {

    public static void main(String[] args) {
        SpringApplication.run(NacosProviderApplication.class, args);
        System.out.println("=================NacosProviderApplication");
    }

    @Value("${server.port}")
    private int port;

    @RestController
    class EchoController {
        @RequestMapping(value = "/echo/{string}", method = RequestMethod.GET)
        public String echo(@PathVariable String string) {
            return "Hello Nacos Discovery " + string + ",port:"+port;
        }
    }
}

(2)application.properties:主要提供Nacos的注册地址等环境信息

server.port=8071
spring.application.name=service-provider
spring.cloud.nacos.discovery.enabled=true
spring.cloud.nacos.discovery.server-addr=127.0.0.1:3333,127.0.0.1:4444,127.0.0.1:5555

接下来是最重要的两个配置文件。

(3)build.gradle:作为构建工具最核心的配置文件。这个配置文件我总结主要可以做下面几件事情:

a.声明需要使用的各种插件plugin,比如我们这里使用springboot的bootJar打包插件;

b.声明依赖仓库repositories:本地仓库、远程仓库等。我们本例子尽可能贴近项目实际情况将自行搭建一个Nexus远程仓库作为依赖仓库;

c.声明项目需要的依赖dependencies:主要是内部和第三方的各类jar等,包含运行时使用和编译时使用的jar;

d.引入子配置文件如apply from: 'common.gradle',复合多个不同工程等;

group 'org.example'
version '1.0-SNAPSHOT'
//禁止springboot gradle插件依赖管理功能
ext.disableDependencyManagementBom = true

buildscript{
    //注意这个repositories必须要有,否则会报错。可以使用本地仓库和远程仓库
    repositories{
        mavenCentral()
    }
    dependencies{
        classpath 'org.springframework.boot:spring-boot-gradle-plugin:2.0.8.RELEASE'
        classpath 'org.springframework.boot:spring-boot-loader-tools:2.0.8.RELEASE'
        classpath 'org.springframework:spring-core:5.0.12.RELEASE'
        classpath 'org.apache.commons:commons-compress:1.14'
    }
}

//注意这里使用org.springframework.boot的bootJar插件因此要引入这个插件
apply plugin: "org.springframework.boot"
apply plugin: 'java'
apply plugin: 'war'

//引入common.gradle辅助配置文件
apply from: 'common.gradle'

//声明仓库:一定要有否则所有jar都会找不到
repositories {
    mavenCentral()
}


dependencies {

    //这里存在nacos-client和httpclient冲突需要进行exclude
    compile('org.springframework.cloud:spring-cloud-starter-alibaba-nacos-discovery:0.2.2.RELEASE'){
        exclude group:'com.alibaba.nacos', module: 'nacos-client'
        exclude group:'org.apache.httpcomponents', module: 'httpclient'
    }

    //这里存在hibernate-validator和httpclient冲突需要进行exclude
    compile('org.springframework.boot:spring-boot-starter-web:2.0.8.RELEASE'){
        exclude group:'org.hibernate', module: 'hibernate-validator'
        exclude group:'org.apache.httpcomponents', module: 'httpclient'
    }

    //引入合适的版本进行替换,结合common.gradle的DuplicatesStrategy.INCLUDE
    compile 'com.alibaba.nacos:nacos-client:1.1.0'
    compile 'org.hibernate:hibernate-validator:5.1.0.Final'
    compile 'org.apache.httpcomponents:httpclient:4.5.5'
}

在本例中,我们暂时使用了本地仓库后面远程仓库搭建后修改过来,同时引入了common.gradle文件辅助构建文件。这个common.gradle构建文件主要是声明一些我们使用的Task任务(Task是Gradle最基本的单元),实际的构建行为也是在这个文件里面定义的。

(4)common.gradle:声明各种Task任务,实际执行构建动作(任务为bootJar)的文件。

//JDK编译级别
def compatibilityVersion = 1.8
sourceCompatibility = compatibilityVersion
targetCompatibility = compatibilityVersion
//META-INF
version = "1.0.0.RELEASE"

ext{
    companyEngName = "yang"
    companyChName = "杨"
    compilePath = "build/classes"
}

//jar归档信息
ext.sharedManifest = manifest{
    attributes 'Built-company': companyEngName
    attributes 'Implementation-Title' : project.name
    attributes 'Implementation-Version' : version
    attributes 'Gradle-Version' : gradle.gradleVersion
    attributes 'Build-Jdk' : compatibilityVersion
    attributes 'Build-Version' : version + "Build" + new Date().format('yyyyMMddHHmmss')
    attributes 'Build-Verdor' : companyChName
    attributes 'Created-Time' : new Date().format('yyyy-MM-dd HH:mm:ss')
}

war{
    enabled = true
}

//必须要加这个task,否则构建时会报不存在该task导致无法构建
task compileDebugSources{
}

//禁掉jar task,一般都不用原生的jar而是使用插件提供的打包任务如bootjar
jar.enabled = false

// 将依赖包复制到lib目录
task copyJar(type: Copy) {
    // 清除lib目录的历史文件
    delete "build\libs\lib"
    from configurations.compileClasspath
    into "build\libs\lib"
}

// 拷贝class文件
task copyClassFile(type: Copy) {
    // 清除classes目录的历史文件
    delete "build\libs\classes"
    from('src/main/java')
    into 'build/libs/classes'
}

// 拷贝配置文件
task copyConfigFile(type: Copy) {
    // 清除resources配置目录的历史文件
    delete "build\libs\resources"
    from('src/main/resources')
    into 'build/libs/classes'
}

// 配置bootJar进行打包:真正进行构建动作的任务
bootJar {
    baseName = companyEngName
    appendix = project.name
    archiveName = baseName + "-" + appendix + new Date().format('yyyyMMddHHmmss') + "." + extension
    //jar重复冲突时的策略:以最后一个为准。这个有多种参数使用INCLUDE主要是针对有jar
    //冲突时使用最后一个,避免了jar冲突导致无法构建。如本例就有nacos-client等jar存在冲突
    duplicatesStrategy = DuplicatesStrategy.INCLUDE
    // libs目录的历史文件清除和拷贝任务
    dependsOn copyJar
    dependsOn copyClassFile
    dependsOn copyConfigFile
    // 声明其它manifest信息,主要在META-INF文件中体现
    manifest {
        from sharedManifest
    }
    //将libs临时目录下生成的待打包文件,统一整合打包到同一个jar里
    //注意这里不可以放在manifest里面,否则会报已经构建无法进行更改的错误,
    //有很多其它博客误导大家就是放manifest里面了导致报错
    from {
        configurations.runtimeClasspath.files.collect { "libs/$it.name" }.join(' ')
    }
}

在这里重点关注bootJar任务,这个任务原本是SpringBoot自动给我们提供出来的,但是默认提供出来的这个任务构建出来的工程jar没办法自定义,因此我们进行了改写从而可以自定义(比如添加manifest描述、jar包命名规则定义等)。

我们看下这个bootJar任务主要做些什么事?首先我们可以想一下如果让我们手工构建,我们需要做哪些事。首先我们会想到我们编写的文件有哪些文件、哪些是class文件、哪些是依赖的jar包、哪些是资源文件、哪些是配置文件等等,这些文件是不是都要放到jar包里发布出去的。

想清楚这一点很重要,因为这一点直接影响了我们要怎么编写构建脚本。就针对本例来说,我们需要把class文件、resources下的配置文件都打包到classes目录下,同时工程还依赖了很多jar包这些包都不在工程的/lib目录下而是引用了maven仓库的,因此这些间接引用的jar依赖也需要打包到jar工程里。明确后开始解析bootJar任务。

// 配置bootJar进行打包:真正进行构建动作的任务
bootJar {
    baseName = companyEngName
    appendix = project.name

    //打包的jar名
    archiveName = baseName + "-" + appendix + new Date().format('yyyyMMddHHmmss') + "." + extension
    //jar重复冲突时的策略:以最后一个为准
    duplicatesStrategy = DuplicatesStrategy.INCLUDE
    // 将工程依赖的jar拷贝到临时目录build\libs\lib下
    dependsOn copyJar

    //将工程中所有的class文件拷贝到临时目录build/libs/classes下
    dependsOn copyClassFile
    // 将工程中所有的配置文件拷贝到临时目录build/libs/classes下
    dependsOn copyConfigFile
    // 声明自定义的manifest信息
    manifest {
        from sharedManifest
    }
    from {   //将libs目录下所有文件统一打包到一个jar里
        configurations.runtimeClasspath.files.collect { "libs/$it.name" }.join(' ')
    }
}

上面copyJar、copyClassFile、copyConfigFile分别就是进行简单的文件移动而已,如果有哪些文件是不需要移动需要剔除的可以结合Exclude命令进行剔除。

最后在控制台输入:gradle bootJar  就可以在build/libs目录下给我们自动构建出一个jar了:

我们用解压工具打开这个jar看下内容:

最后,我们通过控制台命令 jar -jar xxxxx.jar运行这个jar,可以看到打包后的工程正常发布了:

要特别注意使用gradle编写脚本时遇到了不少坑,经过一整天摸索才逐个解决,在gradle文件中都强调注释出来了,如果遇到可以往这个方向思考。

(二)搭建jenkins环境并自动关联打包好的工程jar进行自动发布

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/940899.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号