【SpringBoot】配置文件 && 日志输出 && lombok

文章目录

  • 概述
  • [Ⅰ. 什么是 Spring Boot 配置文件](#Ⅰ. 什么是 Spring Boot 配置文件)
  • [Ⅱ. `properties` 配置文件:`@Value` && `@PostConstruct`](#Ⅱ. properties 配置文件:@Value && @PostConstruct)
  • [Ⅲ. `yml` 配置文件](#Ⅲ. yml 配置文件)
    • 一、配置不同数据类型
    • [二、Map(字典 / 键值对)](#二、Map(字典 / 键值对))
    • [三、List(集合 / 数组)](#三、List(集合 / 数组))
      • [✅ 简单列表](#✅ 简单列表)
      • [✅ 列表中的 Map](#✅ 列表中的 Map)
      • [✅ Map 中包含 List](#✅ Map 中包含 List)
    • [四、`@ConfigurationProperties` 读取 Map 和 List](#四、@ConfigurationProperties 读取 Map 和 List)
  • [Ⅳ. 日志级别的分类](#Ⅳ. 日志级别的分类)
  • [Ⅴ. 日志配置](#Ⅴ. 日志配置)
  • [Ⅵ. 配合 lombok 进行日志输出](#Ⅵ. 配合 lombok 进行日志输出)

概述

  1. .properties 文件以键值类型配置,而 .yml 文件采用树形配置方式。
  2. 读取配置文件内容,使用 @Value 注解,注解内使用 "${}" 的格式读取对应内容。
  3. yml 层级之间严格使用换行缩进的方式配置,keyvalue 之间使用冒号加空格的方式设置,并且空格不可省略
  4. properties 作为早期并且默认的配置文件格式,其配置存在一定的冗余数据,而使用 yml 可以很好的解决数据冗余的问题,但不适合复杂配置。
  5. yml 可以和 properties 共存,如果存在冲突的内容,优先读取 properties 文件中的内容

Ⅰ. 什么是 Spring Boot 配置文件

Spring Boot 支持并定义了配置文件的格式,也在另一个层面达到了规范其他框架集成到 Spring Boot 的目的。很多项目或者框架的配置信息也放在配置文件中,比如:

  1. 项目的启动端口
    1. Spring Boot 内置了 Tomcat 服务器,默认端口号是 8080,但是用户电脑上 8080 端口号有可能就被其他应用程序占用了,所以 Spring Boot 需要支持让用户自定义端口号。
  2. 数据库的连接信息 (包含用户名和密码的设置)
    1. 为了更方便简单的访问数据库,出现了一些持久层框架,其实就是对 JDBC 进行了更深层次的封装。让用户通过简单几行代码就可完成数据库的访问。但是不同的应用程序访问的数据库不同,这些持久层框架就需要支持用户可以自定义配置数据库的连接信息。
  3. 第三方系统的调用密钥等信息
  4. 用于发现和定位问题的普通日志和异常日志等

Spring Boot 配置文件有以下三种:

  • application.properties
  • application.yml(是 yaml 的简写)
  • application.yaml

当应用程序启动时,Spring Boot 会自动从 classpath 路径找到并加载 application.propertiesapplication.yaml 或者 application.yml 文件。

也可以通过 spring.config.name 指定文件路径和名称,参考https://docs.spring.io/spring-boot/reference/features/external-config.html#features.external-config.files

Ⅱ. properties 配置文件:@Value && @PostConstruct

官方配置文档

基本的语法是键值对的形式,键值对之间用 = 隔开,如下所示:

properties 复制代码
# 配置项⽬端⼝号
server.port=9090

#配置数据库连接信息
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/testdb?characterEncoding=utf8&useSSL=false
spring.datasource.username=root
spring.datasource.password=root

读取的时候,使用 @Value 注解搭配 ${} 格式读取,如下所示:

java 复制代码
@Controller
public class demo1 {
    @Value("${spring.datasource.url}")
    private String url;

    @Value("${spring.datasource.username}")
    private String name; // 不需要和键同名

    @Value("${spring.datasource.password}")
    private String passwd; // 不需要和键同名

    @PostConstruct
    public void init() {
        System.out.println(url);
        System.out.println(name);
        System.out.println(passwd);
    }
}

@PostConstruct 注解的方法会在 当前 Bean Spring 完全初始化之后 自动执行一次,常用于初始化逻辑。

执行顺序如下所示:

Java 复制代码
static代码块(类加载时) → 构造方法 → 依赖注入 → @PostConstruct -> Bean ready

💥注意: static 代码块是在类加载阶段就执行的,比 @PostConstruct 要早得多

Ⅲ. yml 配置文件

yml 是树形结构的配置文件,它的基础语法是 "key: value",其中 keyvalue 之间使用英文冒号加空格的方式组成,并且空格不可省略

yaml 复制代码
spring:
  datasource:
    url: jdbc:mysql://127.0.0.1:3306/testdb?characterEncoding=utf8&useSSL=false
    username: root
    password: root
    
#正确的配置方式
mykey1: java

#错误的配置方式❌
mykey2:java

注意: value 值默认不用加上单引号或者双引号

yml 读取配置的方式和 properties 相同,使用 @Value 注解即可,如下所示:

java 复制代码
@Controller
public class demo2 {
    @Value("${spring.datasource.url}")
    private String url;

    @Value("${spring.datasource.username}")
    private String name; // 不需要和键同名

    @Value("${spring.datasource.password}")
    private String passwd; // 不需要和键同名

    @Value("${mykey1}")
    private String mykey; // 不需要和键同名

    @PostConstruct
    public void init() {
        System.out.println(url);
        System.out.println(name);
        System.out.println(passwd);
        System.out.println(mykey);
    }
}

一、配置不同数据类型

注意对应的类型在 java 后端接收的时候要使用对应的类型接收,不然容易出现类型不匹配的错误!

yaml 复制代码
# 字符串
string.value: Hello

# 布尔值,true或false
boolean.value1: true
boolean.value2: false

# 整数
int.value: 10

# 浮点数
float.value: 3.14159

# Null,用~表示
null.value: ~

# 空字符串
# 虽然直接后面什么都不加就可以了,但这种方式不直观,更多的表示是使用引号括起来
empty.value: ''

二、Map(字典 / 键值对)

YAML 中的 Map 表示的是一组 key: value 键值对,和 Java 的 Map<String, Object> 类似。

yaml 复制代码
database:
  host: localhost
  port: 3306
  username: root
  password: 123456

可以理解为:

json 复制代码
{
  "database": {
    "host": "localhost",
    "port": 3306,
    "username": "root",
    "password": "123456"
  }
}

三、List(集合 / 数组)

YAML 中的 List 是通过 -(短横线)表示的。

✅ 简单列表

yaml 复制代码
fruits:
  - apple
  - banana
  - orange

相当于:

json 复制代码
{
  "fruits": ["apple", "banana", "orange"]
}

✅ 列表中的 Map

yaml 复制代码
servers:
  - name: server1
    ip: 192.168.1.1
  - name: server2
    ip: 192.168.1.2

相当于 Java 中的 List<Map<String, String>>

json 复制代码
{
  "servers": [
    { "name": "server1", "ip": "192.168.1.1" },
    { "name": "server2", "ip": "192.168.1.2" }
  ]
}

✅ Map 中包含 List

yaml 复制代码
user:
  name: liren
  hobbies:
    - coding
    - hiking
    - reading

等同于:

json 复制代码
{
  "user": {
    "name": "liren",
    "hobbies": ["coding", "hiking", "reading"]
  }
}

四、@ConfigurationProperties 读取 Map 和 List

yaml 复制代码
myapp:
  name: liren
  tags:
    - java
    - spring
    - yaml
  metadata:
    version: v1.0
    author: liren dada
  servers:
    - name: server1
      ip: 192.168.1.1
    - name: server2
      ip: 192.168.1.2

创建如下配置类:

java 复制代码
@Data
@Component
@ConfigurationProperties("myapp") // 注意名称要对应
public class MyApp {
    private String name;                  // 普通字段
    private List<String> tags;            // List
    private Map<String, String> metadata; // Map
    private List<Server> servers;         // 嵌套自定义对象
    
    @Data
    public static class Server {
        private String name;
        private String ip;
    }
}

然后使用配置类:

java 复制代码
@Controller
public class demo {
    @Autowired
    private MyApp app;

    @PostConstruct
    public void init() {
        System.out.println(app);
    }
}

// 运行结果:
MyApp(name=liren, tags=[java, spring, yaml], metadata={version=v1.0, author=liren dada}, servers=[Server(name=server1, ip=192.168.1.1), Server(name=server2, ip=192.168.1.2)])

Ⅳ. 日志级别的分类

日志的级别从高到低依次为:FATAL、ERROR、WARN、INFO、DEBUG、TRACE

  • FATAL:致命信息,表示需要立即被处理的系统级错误。
  • ERROR:错误信息,级别较高的错误日志信息,但仍然不影响系统的继续运行。
  • WARN:警告信息,不影响使用,但需要注意的问题。
  • INFO:普通信息,用于记录应用程序正常运行时的一些信息,例如系统启动完成、请求处理完成等。
  • DEBUG:调试信息,需要调试时候的关键信息打印。
  • TRACE:追踪信息,比DEBUG更细粒度的信息事件(除非有特殊用意,否则请使用DEBUG级别替代)。

Ⅴ. 日志配置

一、配置日志级别

​ 日志级别配置只需要在配置文件中设置 logging.level 配置项即可,如下所示:

​ Properties配置:

yaml 复制代码
logging.level.root=debug

​ yml配置:

yaml 复制代码
logging:
  level:
    root: debug

二、日志持久化

日志持久化有两种方式:

  1. 配置日志文件名
  2. 配置日志的存储目录

​ 若两种方式同时存在,则以配置日志文件名的方式为准!

配置日志文件名

​ Properties 配置:

yaml 复制代码
logging.file.name=logger/springboot.log

​ yml 配置:

yaml 复制代码
# 设置日志文件的文件名(可以跟绝对路径或者相对路径。)
logging:
  file:
    name: logger/springboot.log

配置日志的存储目录

​ Properties 配置:

yaml 复制代码
logging.file.path=D:/temp

​ yml 配置:

yaml 复制代码
# 设置日志文件的目录
logging:
  file:
    path: D:/temp

这种方式只能设置日志的路径,文件名固定为 spring.log

使用 logback-spring.xml 配置日志

在抽奖系统项目中使用到了用 xml 文件来配置日志,如下所示,具体内容忘记了可以查阅 gpt:

xml 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<configuration  scan="true" scanPeriod="60 seconds" debug="false">
    <!-- springProfile作用:进行环境隔离,区分开发环境和生产环境 -->
    <springProfile name="dev">
        <!-- appender是输出器,这里输出到控制台,核心是这个class,name只是下面要用于绑定日志级别的标识符 -->
        <appender name="console" class="ch.qos.logback.core.ConsoleAppender">
            <!-- encoder作用:日志格式 -->
            <encoder>
                <pattern>%d{HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n%ex</pattern>
            </encoder>
        </appender>

        <!-- root日志级别设置为info,所有日志从 INFO 级别开始往上打印,并且输出到 console -->
        <root level="info">
            <appender-ref ref="console" />
        </root>
    </springProfile>

    <springProfile name="prod,test">
        <!-- 定义变量 -->
        <property name="logback.logErrorDir" value="/root/lottery-system/logs/error"/>
        <property name="logback.logInfoDir" value="/root/lottery-system/logs/info"/>
        <property name="logback.appName" value="lotterySystem"/>
        <!-- 给整个 Logback 日志上下文起"名字"为lotterySystem-->
        <contextName>${logback.appName}</contextName>

        <!-- ERROR级别的日志配置如下 -->
        <appender name="fileErrorLog" class="ch.qos.logback.core.rolling.RollingFileAppender">
            <!--
                日志名称,如果没有File 属性,那么只会使用FileNamePattern的文件路径规则
                如果同时有<File>和<FileNamePattern>,那么当天日志是<File>,明天会自动把今天
                的日志改名为今天的日期。即,<File> 的日志都是当天的。
            -->
            <File>${logback.logErrorDir}/error.log</File>

            <!-- 日志level过滤器,保证error.xxx.log中只记录ERROR级别的日志-->
            <filter class="ch.qos.logback.classic.filter.LevelFilter">
                <level>ERROR</level>
                <onMatch>ACCEPT</onMatch>
                <onMismatch>DENY</onMismatch>
            </filter>

            <!--滚动策略(按天滚动),按照时间滚动 TimeBasedRollingPolicy-->
            <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
                <!--文件路径,定义了日志的切分方式------把每一天的日志归档到一个文件中,以防止日志填满整个磁盘空间-->
                <FileNamePattern>${logback.logErrorDir}/error.%d{yyyy-MM-dd}.log</FileNamePattern>

                <!--只保留最近14天的日志-->
                <maxHistory>14</maxHistory>

                <!--用来指定日志文件的上限大小,那么到了这个值,就会删除旧的日志-->
                <!--<totalSizeCap>1GB</totalSizeCap>-->
            </rollingPolicy>

            <!--日志输出编码格式化-->
            <encoder>
                <charset>UTF-8</charset>
                <pattern>%d [%thread] %-5level %logger{36} %line - %msg%n%ex</pattern>
            </encoder>
        </appender>

        <!--INFO级别的日志配置如下-->
        <appender name="fileInfoLog" class="ch.qos.logback.core.rolling.RollingFileAppender">
            <!--日志名称,如果没有File 属性,那么只会使用FileNamePattern的文件路径规则
                如果同时有<File>和<FileNamePattern>,那么当天日志是<File>,明天会自动把今天
                的日志改名为今天的日期。即,<File> 的日志都是当天的。
            -->
            <File>${logback.logInfoDir}/info.log</File>

            <!--自定义过滤器,保证info.***.log中只打印INFO级别的日志, 填写全限定路径-->
            <!-- 因为内置的 LevelFilter 只能过滤一个级别或以上,所以才要自定义 -->
            <filter class="com.example.lotterysystem.common.filter.InfoLevelFilter"/>

            <!--滚动策略,按照时间滚动 TimeBasedRollingPolicy-->
            <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
                <!--文件路径,定义了日志的切分方式------把每一天的日志归档到一个文件中,以防止日志填满整个磁盘空间-->
                <FileNamePattern>${logback.logInfoDir}/info.%d{yyyy-MM-dd}.log</FileNamePattern>

                <!--只保留最近14天的日志-->
                <maxHistory>14</maxHistory>

                <!--用来指定日志文件的上限大小,那么到了这个值,就会删除旧的日志-->
                <!--<totalSizeCap>1GB</totalSizeCap>-->
            </rollingPolicy>

            <!--日志输出编码格式化-->
            <encoder>
                <charset>UTF-8</charset>
                <pattern>%d [%thread] %-5level %logger{36} %line - %msg%n%ex</pattern>
            </encoder>
        </appender>

        <!-- 所有日志 ≥INFO 的都会触发 -->
        <root level="info">
            <appender-ref ref="fileErrorLog" />
            <appender-ref ref="fileInfoLog"/>
        </root>
    </springProfile>
</configuration>

💥注意: 需要在项目配置文件中添加该文件的路径

properties 复制代码
## logback xml ##
logging.config=classpath:logback-spring.xml 

spring.profiles.active=dev
#spring.profiles.active=prod

Ⅵ. 配合 lombok 进行日志输出

​ 添加 lombok 依赖:

xml 复制代码
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <optional>true</optional>
</dependency>

​ 在想要使用日志的类中添加注解即可:

java 复制代码
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.RestController;

@Slf4j
@RestController
public class LogController {
    public void log(){
        log.info("--------------要输出日志的内容----------------");
    }
}
相关推荐
ChineHe2 小时前
Gin框架基础篇002_获取/绑定请求参数
后端·golang·gin
C+++Python2 小时前
如何选择合适的锁机制来提高 Java 程序的性能?
java·前端·python
IT_陈寒2 小时前
JavaScript 性能优化:7 个 V8 引擎偏爱的编码模式让你提速 40%
前端·人工智能·后端
long3162 小时前
类与对象 | 低级别设计 (LLD)
java·spring boot·学习·程序人生·spring·设计模式·学习方法
专注于大数据技术栈2 小时前
java学习--String、StringBuilder、StringBuffer 的核心区别
java·学习
我命由我123452 小时前
Java 开发问题:包名 ‘com.my.compressimagetest‘ 与同名的类发生冲突
java·开发语言·学习·java-ee·intellij-idea·学习方法·intellij idea
⑩-2 小时前
Sleep与Wait的区别
java·开发语言
程序员阿鹏2 小时前
List和Set的区别
java·开发语言·数据结构·后端·list
CHANG_THE_WORLD2 小时前
6.2.在汇编层面,数据本身没有类型
java·服务器·汇编