SpringBoot运维实用篇

本文最后更新于:13 天前

SpringBoot程序的打包与运行

SpringBoot工程可以基于java环境下独立运行jar文件启动服务

  1. SpringBoot工程执行mvn命令 package 进行打包;
  2. 执行jar命令:java –jar 工程名.jar 运行程序。

程序打包

SpringBoot程序是基于Maven创建的,在Maven中提供有打包的指令,叫做package。本操作可以在Idea环境下执行:

1
mvn package

打包后会产生一个与工程名类似的jar文件,其名称是由 模块名+版本号+.jar 组成的。

程序运行

程序包打好以后,就可以直接执行了。在程序包所在路径下,执行指令:

1
java -jar 工程包名.jar

执行程序打包指令后,程序正常运行,与在Idea下执行程序没有区别。

端口占用解决方案

在DOS环境下启动SpringBoot工程时,可能会遇到端口占用的问题:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 查询端口
netstat -ano

# 查询指定端口
netstat -ano | findstr "端口号"

# 根据进程PID查询进程名称
tasklist | findstr "进程PID号"

# 根据PID杀死任务
taskkill /F /PID "进程PID号"

# 根据进程名称杀死任务
taskkill -f -t -im "进程名称"

配置高级

临时属性

  1. 使用jar命令启动SpringBoot工程时可以使用临时属性替换配置文件中的属性;
  2. 临时属性添加方式:java –jar 工程名.jar –-属性名=值
  3. 多个临时属性之间使用空格分隔;
  4. 临时属性必须是当前boot工程支持的属性,否则设置无效。

临时属性设置

程序包打好以后,里面的配置都已经是固定的了,比如配置了服务器的端口是8080。如果启动项目,发现服务器上已经有应用启动起来并且占用了8080端口,难道要重新把打包好的程序修改一下吗?

SpringBoot提供了灵活的配置方式,如果你发现你的项目中有个别属性需要重新配置,可以使用临时属性的方式快速修改某些配置。方法也特别简单,在启动的时候添加上对应参数就可以了:

1
java –jar springboot.jar –-server.port=80

上面的命令是启动SpringBoot程序包的命令,在命令输入完毕后,空一格,然后输入两个-号。后面按照属性名=属性值的形式添加对应参数就可以了。这里的格式不是yaml中的书写格式,当属性存在多级名称时,中间使用点分隔,和 properties 文件中的属性格式完全相同。

要修改的属性不止一个时,可以按照上述格式继续写,属性与属性之间使用空格分隔:

1
java –jar springboot.jar –-server.port=80 --logging.level.root=debug

属性加载优先顺序

程序配置受两个地方控制了,第一配置文件,第二临时属性。临时属性的加载优先级要高于配置文件的。

官方文档中可以查看配置读取的优先顺序:https://docs.spring.io/spring-boot/docs/current/reference/html/spring-boot-features.html#boot-features-external-config

开发环境中使用临时属性

项目上线时通过命令行输入的临时属性必须是正确的,在开发环境Idea界面下如何测试临时属性呢?

打开SpringBoot引导类的运行界面,在里面找到配置项。其中『Program arguments』对应的位置就是添加临时属性的:

带属性启动SpringBoot程序,为程序添加运行属性


做到这里其实可以产生一个思考了,运行SpringBoot引导类中main方法的时候,使用的是main方法的参数args,并最终传递给了run方法,在Idea中配置的临时参数就是通过这个位置传递到我们的程序中的。

言外之意,这里如果不用这个args是不是就断开了外部传递临时属性的入口呢?是这样的,我们可以使用下面的调用方式,这样外部临时属性就无法进入到SpringBoot程序中了。

  • 不携带参数启动SpringBoot程序

    1
    2
    3
    public static void main(String[] args) {
    SpringApplication.run(SSMPApplication.class);
    }
  • 通过编程形式带参数启动SpringBoot程序,为程序添加运行参数

    1
    2
    3
    4
    5
    public static void main(String[] args) {
    String[] arg = new String[1];
    arg[0] = "--server.port=8080";
    SpringApplication.run(SSMPApplication.class, arg);
    }

配置文件

配置文件分类

SpringBoot提供了配置文件和临时属性的方式来对程序进行配置。配置文件我们一直在使用,只不过我们用的只是SpringBoot提供的4级配置文件中的其中一个级别。4个级别分别是:

  • 类路径下配置文件(一直使用的是这个,也就是resources目录中的application.yml文件)
  • 类路径下config目录下配置文件
  • 程序包所在目录中配置文件
  • 程序包所在目录中config目录下配置文件

上述4种文件是提供了4种配置文件书写的位置,功能都是一样的,都是做配置的。只不过4种配置文件如果同时存在的话,有一个优先级的问题,加载优先顺序为:

  1. file :config/application.yml 【最高】
  2. file :application.yml
  3. classpath:config/application.yml
  4. classpath:application.yml 【最低】

其中,1级与2级留做系统打包后设置通用属性,1级常用于运维经理进行线上整体项目部署方案调控;3级与4级用于系统开发阶段设置通用属性,3级常用于项目经理进行整体项目属性调控。


总结:

  1. 配置文件分为4种:

    • 项目类路径配置文件:服务于开发人员本机开发与测试
    • 项目类路径config目录中配置文件:服务于项目经理整体调控
    • 工程路径配置文件:服务于运维人员配置涉密线上环境
    • 工程路径config目录中配置文件:服务于运维经理整体调控
  2. 多层级配置文件间的属性采用叠加并覆盖的形式作用于程序。

自定义配置文件

自定义配置文件方式有如下两种:

  • 方式一:使用临时属性设置配置文件名,注意仅仅是名称,不要带扩展名

  • 方式二:使用临时属性设置配置文件路径,这个是全路径名

    也可以设置加载多个配置文件:

目前演示的是SpringBoot单体项目,就是单服务器版本。其实企业开发现在更多的是使用基于SpringCloud技术的多服务器项目。这种配置方式和我们现在学习的完全不一样,所有的服务器将不再设置自己的配置文件,而是通过配置中心获取配置,动态加载配置信息,集中管理。

多环境开发

自己电脑上写的程序最终要放到别人的服务器上去运行。每个计算机环境不一样,这就是多环境。常见的多环境开发主要兼顾3种环境设置:

  • 开发环境——自己用的
  • 测试环境——自己公司用的
  • 生产环境——甲方爸爸用的。

因为这是绝对不同的三台电脑,所以环境肯定有所不同,比如连接的数据库不一样,设置的访问端口不一样等等。

多环境开发(yaml单一文件版)

  1. 多环境开发需要设置若干种常用环境,例如开发、生产、测试环境;
  2. yaml格式中设置多环境使用 --- 区分环境设置边界;
  3. 每种环境的区别在于加载的配置属性不同;
  4. 启用某种环境时需要指定启动时使用该环境。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
spring:
profiles:
active: pro # 默认启动pro
---
spring:
profiles: pro # 环境名
server:
port: 80
---
spring:
profiles: dev # 环境名
server:
port: 81
---
spring:
profiles: test # 环境名
server:
port: 82

其中关于环境名称定义上述格式是过时格式,标准格式如下:

1
2
3
4
spring:
config:
activate:
on-profile: pro

多环境开发(yaml多文件版)

将所有的配置都放在一个配置文件中,尤其是当每一个配置应用场景都不一样时,显然不合理。于是就有了将一个配置文件拆分成多个配置文件的想法。拆分后,每个配置文件中写自己的配置,主配置文件中写清楚用哪一个配置文件就好了。即使用独立配置文件定义环境属性,独立配置文件便于线上系统维护更新并保障系统安全性。

因为每一个环境配置文件都是配置自己的项,所以连名字都不用写里面了。那问题是如何区分这是哪一组配置呢?使用文件名区分。文件的命名规则为:application-环境名.yml

  • 主配置文件中设置公共配置(全局)
  • 环境分类配置文件中常用于设置冲突属性(局部)

多环境开发(properties多文件版)

SpringBoot最早期提供的配置文件格式是properties格式的,这种格式的多环境配置与yaml很相似。

文件的命名规则为:application-环境名.properties,properties文件多环境配置仅支持多文件格式。

多环境开发独立配置文件书写技巧

为了方便维护可以基于多环境开发做配置独立管理,使用group属性设置配置文件分组,便于线上维护管理。


多环境开发控制

最后思考一个冲突问题。maven和SpringBoot同时设置多环境的哪个生效?

要想明白冲突问题,要先理清一个关系,究竟谁在多环境开发中其主导地位。maven是做什么的?项目构建管理的,最终生成代码包的;SpringBoot是干什么的?简化开发的。简化,又不是其主导作用。最终还是要靠maven来管理整个工程,所以SpringBoot应该听maven的。

  1. 当Maven与SpringBoot同时对多环境进行控制时,以Mavn为主,SpringBoot使用 @..@ 占位符读取Maven对应的配置属性值
  2. 基于SpringBoot读取Maven配置属性的前提下,如果在Idea下测试工程时pom.xml每次更新需要手动 compile 方可生效。

日志

日志其实就是记录程序日常运行的信息,主要作用如下:

  • 编程期调试代码
  • 运营期记录信息
    • 记录日常运营重要信息(峰值流量、平均响应时长……)
    • 记录应用报错信息(错误堆栈)
    • 记录运维过程数据(扩容、宕机、报警……)

代码中使用日志工具记录日志

  • 日志用于记录开发调试与运维过程消息
  • 日志的级别共6种,通常使用4种即可,分别是DEBUG,INFO,WARN,ERROR
  • 可以通过日志组或代码包的形式进行日志显示级别的控制

  1. 添加日志记录操作

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    @RestController
    @RequestMapping("/books")
    public class BookController {

    //创建记录日志的对象
    private static final Logger log = LoggerFactory.getLogger(BookController.class);

    @GetMapping
    public String getById(){
    System.out.println("springboot is running......");

    //调用日志的API
    log.debug("debug……");
    log.info("debug……");
    log.warn("debug……");
    log.error("debug……");

    return "springboot is running......";
    }
    }

  2. 在yml中设置日志输出级别

    日志设置好以后可以根据设置选择哪些参与记录。这里是根据日志的级别来设置的。日志的级别分为6种,分别是:

    • TRACE:运行堆栈信息,使用率低
    • DEBUG:程序员调试代码使用
    • INFO:记录运维过程数据
    • WARN:记录运维过程报警数据
    • ERROR:记录错误堆栈信息
    • FATAL:灾难信息,合并计入ERROR

    一般情况下,开发时候使用DEBUG,上线后使用INFO,运维信息记录使用WARN即可。下面就设置一下日志级别(日志系统通常都提供了细粒度的控制):

    1
    2
    3
    4
    5
    6
    7
    # 开启debug模式,输出调试信息,常用于检查系统运行状况
    debug: true

    # 设置日志级别,root表示根节点,即整体应用日志级别(可以设置更细粒度的控制)
    logging:
    level:
    root: debug


    设置日志组,控制指定包对应的日志输出级别,也可以直接控制指定包对应的日志输出级别

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    logging:
    # 设置日志组
    group:
    # 自定义组名,设置当前组中所包含的包
    ebank: cc.gaojie.controller,cc.gaojie.service
    level:
    root: warn
    # 为对应组设置日志级别
    ebank: debug
    # 为对包设置日志级别
    cc.gaojie.dao: debug

说白了就是总体设置一下,每个包设置一下,如果感觉设置的麻烦,就先把包分个组,再对组设置。

优化日志对象创建代码

写代码的时候每个类都要写创建日志记录对象,这个可以优化一下,使用前面用过的 lombok 技术给我们提供的工具类即可。导入lombok后使用注解 @Slf4j 注解为类快速添加日志对象,日志对象名为log。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@Slf4j
@RestController
@RequestMapping("/books")
public class BookController{

@GetMapping
public String getById(){
System.out.println("springboot is running......");
log.debug("debug……");
log.info("debug……");
log.warn("debug……");
log.error("debug……");
return "springboot is running......";
}

}

日志输出格式控制

日志已经能够记录了,但是目前记录的格式是SpringBoot给我们提供的,如果想自定义控制就需要自己在yml文件中设置。先分析一下当前日志的记录格式。

对于单条日志信息来说,日期,触发位置,记录信息是最核心的信息。级别用于做筛选过滤,PID与线程名用于做精准分析。了解这些信息后就可以DIY日志格式了。

  • PID:进程ID,用于表明当前操作所处的进程,当多服务同时记录日志时,该值可用于协助程序员调试程序。
  • 所属类/接口名:当前显示信息为SpringBoot重写后的信息,名称过长时,简化包名书写为首字母,甚至直接删除。

简化日志输出格式:

1
2
3
logging:
pattern:
console: "%d - %m%n"

模拟官方日志模板的书写格式:

1
2
3
logging:
pattern:
console: "%d %clr(%p) --- [%16t] %clr(%-40.40c){cyan} : %m %n"

日志文件

日志不能仅显示在控制台上,要把日志记录到文件中,方便后期维护查阅。对于日志文件的使用存在各种各样的策略,例如每日记录,分类记录,报警后记录等。这里主要研究日志文件如何记录。

记录日志到文件中格式非常简单,设置日志文件名即可。

1
2
3
logging:
file:
name: server.log

面对线上的复杂情况,一个文件记录肯定是不能够满足运维要求的,通常会每天记录日志文件,同时为了便于维护,还要限制每个日志文件的大小。下面给出日志文件的常用配置方式:

1
2
3
4
5
logging:
logback:
rollingpolicy:
max-file-size: 3KB
file-name-pattern: server.%d{yyyy-MM-dd}.%i.log

以上格式是基于logback日志技术设置每日日志文件的设置格式,要求容量到达3KB以后就转存信息到第二个文件中。文件命名规则中的%d标识日期,%i是一个递增变量,用于区分日志文件。