0%

Springboot运维实用篇

  • Springboot运维实用篇
    • Springboot工程打包与运行
    • 配置高级
    • 多环境开发
    • 日志

二、运维实用篇

2.1 Springboot工程打包与运行

2.1.1 程序打包

  • 对 Springboot 的 maven 工程进行打包很简单:

    1. 通过 clean 清楚之前的 target 目录。

    2. 省略打包过程中的测试环节(前提是对已经开发的功能都进行过测试且测试通过),通过点击 ② 处的按钮省略,目的是为了防止测试过程对数据库的数据造成影响。

    3. 通过 package 对工程进行打包。生成的 jar 包就在 target 目录下

    4. 我们可以通过在命令行输入 java -jar xxx.jar 来运行项目。

      • 注意:jar 支持命令行启动需要依赖 maven 插件支持,请确认打包时是否具有 SpringBoot 对应的 maven 插件:

        1
        2
        3
        4
        5
        6
        7
        8
        <build>
        <plugins>
        <plugin>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-maven-plugin</artifactId>
        </plugin>
        </plugins>
        </build>

2.2.2 maven打包插件

  • 由前所述,jar 支持命令行启动需要依赖 maven 插件支持,为什么呢?

    • 我们可以尝试在使用该 maven 插件前后,分别打包 springboot 项目,观察得到的 jar 包有什么不同。

      • 使用 maven 插件打包的 jar 包(后缀为 1),后面简称为 1包

        没有使用 maven 插件打包的 jar 包(后缀为 2),后面简称为 2包

      可以看到:

      1. 1包 的大小要明显大于 2包,因为在 1包 中,还打包了依赖的 jar 包以及项目启动类加载器等包。而 2包 中只有项目代码相关的包,不会加入依赖的 jar 包和启动类加载器等包。

      2. 1包2包 的目录结构不一样,实际上,2包 中的内容只是 1包 中的一部分。

      3. META-INF 目录中,有 jar 包的描述文件 MANIFEST.MF

        • 1包MANIFEST.MF

          1
          2
          3
          4
          5
          6
          7
          8
          9
          10
          11
          12
          Manifest-Version: 1.0
          Archiver-Version: Plexus Archiver
          Created-By: Apache Maven 3.6.1
          Built-By: Running Noob
          Build-Jdk: 17.0.8
          Main-Class: org.springframework.boot.loader.JarLauncher
          Start-Class: com.f.springboot.Springboot06SsmpApplication
          Spring-Boot-Version: 3.0.2
          Spring-Boot-Classes: BOOT-INF/classes/
          Spring-Boot-Lib: BOOT-INF/lib/
          Spring-Boot-Classpath-Index: BOOT-INF/classpath.idx
          Spring-Boot-Layers-Index: BOOT-INF/layers.idx
        • 2包MANIFEST.MF

          1
          2
          3
          4
          5
          Manifest-Version: 1.0
          Archiver-Version: Plexus Archiver
          Created-By: Apache Maven 3.6.1
          Built-By: Running Noob
          Build-Jdk: 17.0.8

        1包MANIFEST.MF 中,指明了 JarLauncher 类(jar 启动器,在 org 包中)和启动类 Springboot06SsmpApplication,由此才能找到项目启动的入口。

  • 1包 的各目录的作用做一个简要说明:

    • BOOT-INF 目录下存放程序员开发的项目相关代码的 classes 文件以及依赖的 jar 包。
    • META-INF 目录下存放 jar 包的相关元数据。
    • org 目录下存放用来独立加载运行 springboot 项目的相关类的 classes 文件。

2.2.3 在Linux服务器上运行项目

2.2 配置高级

2.2.1 临时属性设置(有风险,不用)

  • 如果想要临时修改项目的属性配置,例如将项目的 application.yml 中设置的 80 端口改为 8080 端口,则可以在命令行中,通过在命令末尾带上属性来启动 springboot 项目:

    1
    sudo java -jar /usr/local/app/springboot_06_ssmp-0.0.1-SNAPSHOT1.jar --server.port=8080
    • 注意使用临时属性时,要用 properties 中属性配置的格式。

    • 要携带多个临时属性启动 SpringBoot 时,属性间使用空格分隔:

      1
      sudo java -jar /usr/local/app/springboot_06_ssmp-0.0.1-SNAPSHOT1.jar --server.port=8080 --xxx=xxx
  • 属性加载的优先级顺序:

  • 事实上,在命令行后面带上的临时属性,其实就是传给引导类的 args 参数:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    package com.f.springboot;

    import org.mybatis.spring.annotation.MapperScan;
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;

    @SpringBootApplication
    @MapperScan("com.f.springboot.mapper")
    public class Springboot06SsmpApplication {

    public static void main(String[] args) {
    SpringApplication.run(Springboot06SsmpApplication.class, args);
    }

    }
    • 为了提高安全性,可以在方法中将 args 参数去掉:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      package com.f.springboot;

      import org.mybatis.spring.annotation.MapperScan;
      import org.springframework.boot.SpringApplication;
      import org.springframework.boot.autoconfigure.SpringBootApplication;

      @SpringBootApplication
      @MapperScan("com.f.springboot.mapper")
      public class Springboot06SsmpApplication {

      public static void main(String[] args) {
      // 可以在启动boot程序时断开读取外部临时配置对应的入口,也就是去掉读取外部参数的形参
      SpringApplication.run(Springboot06SsmpApplication.class);
      }

      }

2.2.2 ★配置环境

springboot的4级配置文件
  • 在实际项目开发中,至少有两套环境:开发环境和生产环境(其实还有一个测试环境)。

    • 开发环境是我们程序员在开发时的环境,这时我们有一套开发配置。
    • 生产环境是项目实际上线的环境,这时有另一套配置。

    问题是配置的名称都为 application.(properties|yml|yaml),在编写开发环境的配置文件和生产环境的配置文件时,名称会冲突。怎么办?

    • springboot 可以让我们基于现有的配置,再做一套配置,这套新做的配置,可以覆盖现有的配置。步骤为:

      1. 在类的根路径下,也是 resources 目录下,新建 config 目录。

      2. config 目录下创建新的配置文件 application.yml,做一套全新的配置:

        1
        2
        3
        # 应用服务 WEB 访问端口
        server:
        port: 8888
        • 作为对比,这是原先开发环境中的配置:

          1
          2
          3
          4
          5
          6
          7
          8
          9
          10
          11
          12
          13
          14
          15
          16
          17
          18
          19
          20
          21
          # 应用服务 WEB 访问端口
          server:
          port: 80

          # 数据源配置
          spring:
          datasource:
          driver-class-name: com.mysql.cj.jdbc.Driver
          url: jdbc:mysql://localhost:3306/springboot
          username: root
          password: root
          type: com.alibaba.druid.pool.DruidDataSource

          # mybatis-plus配置
          mybatis-plus:
          global-config:
          db-config:
          table-prefix: t_
          id-type: auto # 使用数据库默认的自增策略
          configuration:
          log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
      3. 启动项目,发现端口变为 8888,且项目正常运行。

        • 这两套配置文件之间的合作原则:

          • 重合的部分,级别高的配置(resources/config 目录中的)覆盖级别低的配置(resources 目录中的)。
        • 不重合的部分,配置都会生效,即“合并在一起”了。

          多层级配置文件间的属性采用叠加并覆盖的形式作用于程序

  • 前面是在类的根路径下新建 config 目录,然后创建配置文件,该配置文件优先级高于最原始的配置文件。

    当项目打包成 jar 包以后,如果在 jar 包的同级目录下创建了配置文件,则该配置文件的优先级又要高于类路径下的配置文件

    • 类似的,在 jar 包的同级目录下新建 config 目录,然后创建配置文件,则该配置文件优先级高于前面所有的配置文件。
  • 最终可以发现,SpringBoot 中有 4 级配置文件:

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

    作用:

    • 1 级与 2 级留做系统打包成 jar 包后设置通用属性,1 级常用于运维经理进行线上整体项目部署方案调控。
    • 3 级与 4 级用于系统开发阶段设置通用属性,3 级常用于项目经理进行整体项目属性调控。
  • 之前说过,配置文件的优先级为 properties(最高)> yml > yaml(最低),那么问题来了,是 classpath:config/application.yml 的优先级高,还是 classpath:application.properties 的优先级高?

    • 测试发现,classpath:config/application.yml 的优先级高,说明从优先级上来说,目录的优先级高于配置文件格式类型的优先级

2.2.3 自定义配置文件名称(实际开发中用的少)

  • 配置文件的名称只能是 application.(properties|yml|yaml) 吗,如果是这样,那配置文件的名称相当于直接暴露在外面,有风险性。

    • application.(properties|yml|yaml) 是 springboot 工程默认的配置文件名称,但其实我们可以自定义配置文件的名称。有两种办法来自定义。
      • 假设我们自定义的配置文件名称为 bookconfig.yml
  • 方法一:通过临时属性指定自定义的配置文件名称(无需书写配置文件扩展名)

    • --spring.config.name=bookconfig
  • 方法二:通过临时属性指定文件路径下的配置文件(需要书写配置文件扩展名)

    • --spring.config.location=classpath:bookconfig.yml

      • 注意:指定文件路径下的配置文件时可以指定多个配置,然后后面的会覆盖前面的:

        --spring.config.location=classpath:bookconfig.yml,classpath:book-server.yml

        • 会使用 book-server.yml 配置。
  • 自定义配置文件的说明:

    • 单服务器项目:使用自定义配置文件需求较低。
    • 多服务器项目:使用自定义配置文件需求较高,将所有配置放置在一个目录中,统一管理。
      • 基于 SpringCloud 技术,所有的服务器将不再设置配置文件,而是通过配置中心进行设定,动态加载配置信息。

2.3 ★多环境开发

  • 多环境:生产环境、开发环境、测试环境。

    • 不同环境的配置各不相同。

      • 所谓多环境开发,就是根据不同的环境配置不同的值

      下面我们设置了三种不同的环境,并用 --- 隔开:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      # 要应用的环境
      # 可以在这里写一些公共配置
      spring:
      profiles:
      active: dev
      ---
      # 下面设置了三种不同的环境,用"---"隔开
      # 生产环境
      spring:
      config:
      activate:
      on-profile: pro
      server:
      port: 80
      ---
      # 开发环境
      spring:
      config:
      activate:
      on-profile: dev
      server:
      port: 81
      ---
      # 测试环境
      spring:
      config:
      activate:
      on-profile: test
      server:
      port: 82
      • 另外,应用环境也要用 --- 和设置的环境隔开。

        • 在应用环境中写一些公共配置,在设置的环境中写该环境专有的配置

        • 图中是过时的写法,具体写法还是看上面的代码。

  • 在实际开发中,不会将多环境的配置都写在一个文件中,而是将不同环境的配置用不同的文件来存储。

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

  • 其实就是将多环境的配置从一个文件拆分为多个文件:

    1
    2
    3
    # application-pro.yml文件
    server:
    port: 80
    1
    2
    3
    # application-dev.yml文件
    server:
    port: 81
    1
    2
    3
    # application-test.yml文件
    server:
    port: 82
    1
    2
    3
    4
    5
    # application.yml文件
    # 应用环境
    spring:
    profiles:
    active: dev
    • 注意环境配置文件的命名为 application-xxx.yml

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

  • yaml 版的基本一模一样。

2.3.3 ★多环境开发配置文件书写技巧

  • 多环境开发配置文件书写技巧:

    • 主配置文件中设置公共配置(全局)
    • 环境分类配置文件中常用于设置冲突属性(局部)
  • 根据功能对配置文件中的信息进行进一步拆分,并制作成独立的配置文件,命名规则如下:

    • application-devDB.yml -> 开发环境下数据库配置文件
    • application-devRedis.yml -> 开发环境下缓存配置文件
    • application-devMVC.yml -> 开发环境下MVC配置文件

    使用 include 属性在激活指定环境的情况下,同时对多个环境进行加载使其生效,多个环境间使用逗号分隔:

    1
    2
    3
    4
    spring:
    profiles:
    active: dev
    include: devDB,devMVC
    • 注意:当主环境 dev 与其他环境有相同属性时,主环境属性生效;其他环境中有相同属性时,最后加载的环境属性生效。

      1
      The following profiles are active: devDB,devMVC,dev
      • 生效优先级:dev > devMVC > devDB
  • 从 Spring2.4 版开始使用 group 属性替代 include 属性,降低了配置书写量:

    1
    2
    3
    4
    5
    6
    7
    spring:
    profiles:
    active: dev
    group:
    "dev": devDB,devMVC
    "pro": proDB,proMVC
    "test": testDB,testRedis,testMVC
    • 使用 group 属性定义多种主环境与子环境的包含关系。

    • 注意:使用 group 属性,会覆盖主环境 dev (active) 的内容,最后加载的环境属性生效。

      1
      The following 3 profiles are active: "dev", "devDB", "devMVC"
      • 生效优先级:devMVC > devDB > dev

2.4 ★日志

  • 日志的作用:
    1. 编程期调试代码。
    2. 运营期记录信息。
      • 记录日常运营重要信息(峰值流量、平均响应时长……)
      • 记录应用报错信息(错误堆栈)
      • 记录运维过程数据(扩容、宕机、报警……)
  • 代码中使用日志工具记录日志。

2.4.1 日志基础操作

  • 使用日志记录信息分以下几步:

    1. 创建日志记录对象。

    2. 手工记录日志信息。

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      package com.f.springboot.controller;

      import org.slf4j.Logger;
      import org.slf4j.LoggerFactory;
      import org.springframework.web.bind.annotation.GetMapping;
      import org.springframework.web.bind.annotation.RequestMapping;
      import org.springframework.web.bind.annotation.RestController;


      /**
      * @author fzy
      * @date 2024/2/21 15:30
      */
      @RestController
      @RequestMapping("/books")
      public class BookController {
      // 1.创建记录日志对象
      private static final Logger log = LoggerFactory.getLogger(BookController.class);

      @GetMapping
      public String get() {
      // 2.手工记录日志信息
      log.trace("trace...");
      log.debug("debug...");
      log.info("info...");
      log.warn("warn...");
      log.error("error...");
      return "springboot2...";
      }
      }
      • 日志级别:TRACE < DEBUG < INFO < WARN < ERROR < FATAL

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

        Mybatis笔记 - 2.5 Mybatis集成日志框架logbackSpring笔记 - 3.4 Spring6 启用 Log4j2 日志框架 中均有提到日志相关内容。

    3. application.yml 文件中设置日志输出的级别,该级别及该级别之上的日志将会被记录:

      1
      2
      3
      4
      5
      # 设置日志记录级别为DEBUG
      # root 表示根节点,即整体应用日志级别
      logging:
      level:
      root: debug
    4. 除了设置 root 的日志输出级别,还可以设置日志组,控制指定组对应的日志输出级别,也可以直接控制指定包对应的日志输出级别:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      # 设置日志组,控制指定组对应的日志输出级别
      logging:
      group:
      # 自定义组名,设置组中所包含的包
      controller: com.f.springboot.controller
      model: com.f.springboot.service, com.f.springboot.mapper
      level:
      root: info
      # 设置某个组的日志输出级别
      controller: debug
      model: debug
快速创建日志对象
  • 使用 lombok 提供的注解 @Slf4j 简化开发,减少日志对象的声明操作。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    package com.f.springboot.controller;

    import lombok.extern.slf4j.Slf4j;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;


    /**
    * @author fzy
    * @date 2024/2/21 15:30
    */
    @RestController
    @RequestMapping("/books")
    @Slf4j
    public class BookController {
    // 1.使用@Slf4j创建记录日志对象
    //private static final Logger log = LoggerFactory.getLogger(BookController.class);

    @GetMapping
    public String get() {
    // 2.手工记录日志
    log.trace("trace...");
    log.debug("debug...");
    log.info("info...");
    log.warn("warn...");
    log.error("error...");
    return "springboot2...";
    }
    }

2.4.2 日志输出格式控制

  • 日志在默认格式下,有以下几个部分组成:

    • PID:进程 ID,用于表明当前操作所处的进程,当多服务同时记录日志时,该值可用于协助程序员调试程序。
    • 所属类/接口名:当前显示信息为 SpringBoot 重写后的信息,类的全名称过长时,简化包名书写为首字母,甚至直接删除。
  • 我们可以在 application.yml 配置文件中自定义日志的输出格式(不重要):

    1
    2
    3
    4
    # 设置日志输出的格式
    logging:
    pattern:
    console: "%d - %m%n"
    • %d:日期
    • %m:消息
    • %n:换行

2.4.3 文件记录日志

  • 通过在 application.yml 配置文件中设置记录日志的文件:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    # 设置记录日志的文件
    logging:
    file:
    name: server.log
    logback:
    rollingpolicy:
    # 当日志大小超过4KB时,就新开一个日志文件
    max-file-size: 4KB
    # 日志名称的设置
    file-name-pattern: server.%d{yyyy-MM-dd}.%i.log
    • 日志文件会被保存在整个项目的根路径下。
---------------The End---------------