SpringBoot04-运维相关技术+多环境配置+日志
2026/7/19 10:21:10 网站建设 项目流程

一、 SpringBoot项目的打包和启动

【问题】:在执行mvn package命令的时候,会先执行test命令,将在test中写的crud的操作都执行一遍,此时会有测试数据的增加,为了避免test操作,可以跳过test执行命令

1-1、springboot打包插件:spring-boot-maven-plugin的作用

使用springboot打包插件打出的jar包会比没有使用打包插件打出的jar包更大,内容更多!

1、打包的文件结构的区别

META-INF是 Java 的约定目录,放在classpath下,专门存放框架和 JVM 需要读取的配置元数据。Spring Boot 的自动配置、Java 的 SPI 机制、jar 包清单等都依赖这个目录。

源文件里通常没有META-INF,它是打包时自动生成的。

META-INF/MANIFEST.MF是 Maven/Gradle 打包时自动创建的,描述 jar 包信息。

某些功能必须在源码里手动建META-INF

Spring Boot 自动配置(自定义 starter)

如果你想写一个自己的 starter,就必须手动创建:

2、jar包描述文件MANFEST.MF的区别

3、程序启动时,发现端口被占用

【注意】:

推荐使用进程pid号,杀死进程;因为,进程名称可能会有多个!

1-2、临时属性的设置

示例:使用java -jar启动项目的时候,临时想用另一个端口号启动

(application.yml中用的是80,但是启动的时候,想用8080端口)

1、启动命令行,设置临时属性

【注意】:

属性和application.yml中的key是一致的!

2、在idea中设置启动命令的临时属性:

设置:Program arguments

此时设置的参数,可以在启动类中获取到

所以,出于安全的考虑,可以在启动boot程序时,断开读取外部临时配置对应的入口,也就是去掉读取外部参数的形参:

二、Spring Boot 配置文件application

2-1、多层级Spring Boot 配置文件加载优先级:

若是做一些保密级别较高的项目,数据库等配置信息保密,配置文件可以保存在与project同文件夹的config文件夹中,并且config文件夹没有访问权限

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

2-2、自定义配置文件

1、通过启动参数加载自定义的文件名(无需写配置文件的扩展名)

2、通过通过启动参数加载指定文件路径下的配置文件

【注意】:

1、这两种方式:properties文件和yml格式的文件都是支持的

2、当指定了自定义配置文件的时候,这时若是还有默认的application配置文件,就不是叠加覆盖的形式了,而是就用指定的自定义的配置文件!

【备注】:

2-3、多环境开发下的配置文件

1、多环境

2、YAML 的多 profile 写法(推荐)

如果你使用application.yml可以用---进行多环境分隔。

properties格式的文件,没有这种写法!!!

【注意】:

将每个环境中的公共配置,放在最上面,不同环境的配置,写在不同环境中!

Spring Boot 版本标记环境的语法
2.4 之前spring.profiles: dev
2.4 及之后(推荐)spring.config.activate.on-profile: dev

示例:

# ========== 公共配置 + 激活声明 ========== spring: application: name: my-app profiles: active: dev # ← ✅ 只激活 dev,其他环境配置被忽略 --- # ========== dev 环境配置 ========== spring: config: activate: on-profile: dev # ← 标记:这段配置属于 dev server: port: 8080 datasource: url: jdbc:mysql://localhost:3306/dev_db --- # ========== test 环境配置 ========== spring: config: activate: on-profile: test # ← 标记:这段配置属于 test # 因为上面 active: dev,这段不会加载! server: port: 8081 datasource: url: jdbc:mysql://192.168.1.10:3306/test_db --- # ========== prod 环境配置 ========== spring: config: activate: on-profile: prod # ← 标记:这段配置属于 prod # 同样不会加载 server: port: 80 datasource: url: jdbc:mysql://10.0.0.5:3306/prod_db

【注意】:

这种方式有信息暴露的风险,因为所有的信息都在一个文件中。 所以,可以写多个配置文件。

3、多个配置文件的写法

yml和properties格式的文件,只是写法不同,其余完全一致

【注意】:

1、主配置文件中设置公共配置(全局)

2、环境分类配置文件中常用于设置冲突属性(局部)

4、多环境开发,独立配置文件,书写技巧:

(1)、使用maven占位符

实际开发中,maven可以有配置文件profiles,springboot也有配置文件profiles。

因为springboot是依赖于maven的,所以,一定是maven先运行,所以,springboot可以读取maven的配置文件信息,使用@...@读取

所以,实际开发中,有一个写法:

@profile.name@Maven 占位符,它通常出现在 Spring Boot 项目的配置文件中,表示这个值将在构建(mvn package)时被 Maven 插件替换成实际的值。

需要通过pom.xml中的配置在打包时注入实际的值


实际注入方式(在pom.xml中定义):

<properties> <profile.name>dev</profile.name> </properties>

或者通过<build>resources插件替换变量:

<build> <resources> <resource> <directory>src/main/resources</directory> <filtering>true</filtering> <!-- 开启占位符替换 --> </resource> </resources> </build>

结果:

打包后application.yml中的:

spring: profiles: active: '@profile.name@'

就会被替换成:

spring: profiles: active: dev
# 默认打包(激活 dev) mvn package # application.yml 变成:spring.profiles.active: dev # 显式激活生产环境 mvn package -P pro_env # application.yml 变成:spring.profiles.active: pro

【小提示】:

  1. 只有开启了资源文件的 filtering (<filtering>true</filtering>) 才能让占位符生效

  2. 开发时如果没有打包,IDEA 中运行时不会解析@profile.name@,你可以临时写死或者通过启动参数指定-Dspring.profiles.active=dev

【小结】:

图中 Maven Profile 的典型用法是通过资源过滤,把spring.profiles.active的值"注入"到打包后的配置文件中,两者是配合关系。

【问题】:在idea中,切换默认激活的代码到其他的环境可能会不生效:

这是idea的缓存导致的

解决方式:mvn compile,手工编译

<activation>是否必须?
不是。

  • 不写<activation>:你需要用-P xxx手动选择哪个 Maven profile

  • 写了<activeByDefault>true</activeByDefault>:在没传-P时默认用这个。

维度Maven Profile(图中方式)Spring Bootapplication-{profile}.yml
作用阶段构建时(编译、打包)运行时(项目启动)
控制什么控制构建过程(依赖、插件、资源过滤)控制运行配置(端口、数据库、日志级别)
谁读取MavenSpring Boot
生效时机mvn packagejava -jar启动时

Maven Profile 能做(Spring Boot 做不到)

<profile> <id>dev</id> <dependencies> <!-- dev 环境引入热部署工具 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> </dependency> </dependencies> </profile> <profile> <id>prod</id> <build> <plugins> <!-- prod 环境跳过测试 --> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-surefire-plugin</artifactId> <configuration> <skipTests>true</skipTests> </configuration> </plugin> </plugins> </build> </profile>
(2)、根据功能对配置文件拆分
【写法一】:include属性

Spring Boot 里,一个环境 profile 往往要管理多个功能模块的配置,比如:

  • 数据库(DB)

  • 缓存(Redis)

  • Web MVC

如果全都写在application-dev.yml里,会很臃肿。于是可以拆成多个小的配置文件

  • application-devDB.yml

  • application-devRedis.yml

  • application-devMVC.yml

spring.profiles.include这个属性的作用是:在激活某个环境时,同时再加载额外的配置文件

含义是:

  • 主 profile 是dev→ Spring Boot 会加载application-dev.yml

  • 同时还会加载application-devDB.ymlapplication-devRedis.ymlapplication-devMVC.yml

  • 多个配置文件会合并,最后形成一个完整的环境配置。

【注意】:

此时这些配置文件是有加载顺序的!先顺序加载include中的配置文件,最后加载active中的配置文件(后面的文件信息覆盖前面的文件信息)

【写法二】:group属性(推荐)

YAML 中只有当 key 包含特殊字符时才需要引号。所以,""可以不加

标准写法:

# application.yml spring: profiles: active: local # 只激活一个名字,但实际加载一组配置 group: # 定义 "local" 组 = dev + mysql-local + redis-local local: - dev - mysql-local - redis-local # 定义 "prod" 组 = prod + mysql-prod + redis-prod + sentinel prod: - prod - mysql-prod - redis-prod - sentinel

效果:

# 激活 local,实际加载:application-dev.yml + application-mysql-local.yml + application-redis-local.yml java -jar app.jar --spring.profiles.active=local # 激活 prod,实际加载:application-prod.yml + application-mysql-prod.yml + application-redis-prod.yml + application-sentinel.yml java -jar app.jar --spring.profiles.active=prod

与 include 的区别
特性spring.profiles.groupspring.profiles.include
定义位置application.ymlspring.profiles.group任意 profile 配置文件内
激活方式spring.profiles.active=组名激活某个 profile 后自动 include
用途打包一组 profile 给一个名字某个 profile 激活时自动附带其他 profile

【注意】:加载顺序

1. application.yml(主配置,包含 group 定义) └─ 发现 spring.profiles.active: dev └─ 发现 group.dev = [devDB, devRedis, devMVC] 2. application-dev.yml(active 指定的 profile) └─ 加载 dev 环境的基础配置 3. application-devDB.yml(group 中的第1个) 4. application-devRedis.yml(group 中的第2个) 5. application-devMVC.yml(group 中的第3个) └─ 后面的覆盖前面的同名配置

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

3-1、日志级别

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

3-2、设置某个的日志级别:

3-3、设置分组,对某个分组设置日志级别(推荐)

3-4、快速创建日志对象

【问题】:每个类都要写一遍,很繁琐

private static final Logger logger = LoggerFactory.getLogger(CarController.class);

方式一:使用继承的方式

1、定义一个父类

public class MyLogUtils { protected final Logger logger = LoggerFactory.getLogger(getClass()); }

2、让需要使用日志的类继承这个父类,即可。

方式二:使用 Lombok 的@Slf4j 注解推荐!!!

示例:

完整的配置和使用步骤:

1. 添加Lombok 依赖

Maven项目,在pom.xml里加上:

<dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.32</version> <!-- 版本可根据需要调整 --> <scope>provided</scope> </dependency>

2. 确认 IDE 已启用 Lombok 插件

IntelliJ IDEA:安装 Lombok 插件,并在Preferences > Build, Execution, Deployment > Compiler > Annotation Processors中开启Enable annotation processing

IDEA 的“注解处理”设置作用范围

  • 仅对 IDEA 自己的编译器和代码提示有效

    • 开启后,IDEA 在你写代码、点“运行”按钮时,会调用注解处理器(Annotation Processor),帮你生成loggetter/setter等代码。

    • 这样你在 IDE 里就不会看到报红。

  • 对最终打包没有直接影响,因为打包是 Maven/Gradle 调用javac编译,而javac默认是支持注解处理器的(只要你加了 Lombok 依赖,javac会执行 Lombok 的处理逻辑)。

【注意】:当注解处理开启时,IDE 编译代码时会:

由 Lombok 的处理器在编译阶段生成一个private static final Logger log = LoggerFactory.getLogger(当前类.class);

3. 使用 @Slf4j 注解

然后在类上加@Slf4j,Lombok 就会自动生成一个log日志对象(类型是org.slf4j.Logger)。

4. 日志输出配置

Spring Boot 默认使用Logback,只要在application.propertiesapplication.yml配置日志级别即可,比如:

logging.level.root=INFO logging.level.com.example.demo=DEBUG

【总结】:

  1. 加 Lombok 依赖

  2. IDE 开启注解处理

  3. 类上加@Slf4j

  4. 在代码里直接用log.info()等方法


【回顾】:getClass()方法

getClass()是定义在java.lang.Object中的一个实例方法,它在运行时返回的是实际对象的类,而不是声明它的那个类。


举个例子:

public class LogSupport { public void printClassName() { System.out.println("class: " + getClass()); } } public class CarController extends LogSupport { } public class Demo { public static void main(String[] args) { LogSupport obj = new CarController(); obj.printClassName(); } }

输出:

class: class CarController

你看,尽管printClassName()是写在LogSupport中的,但运行时调用的是obj.getClass(),而obj的实际类型是CarController,所以返回的是CarController.class

所以,你在MyLogUtils类中写了:

protected final Logger logger = LoggerFactory.getLogger(getClass());

谁继承了 LogSupport,调用 getClass() 得到的就是子类的 class 对象

例如:

public class CarController extends LogSupport { // logger 实际是 LoggerFactory.getLogger(CarController.class) }

这就解决了每个类都写LoggerFactory.getLogger(XXX.class)的繁琐问题。

3-5、日志的输出格式

日志输出格式的控制

3-6、文件记录日志

方案1:application.yml中配置

缺点:这种方式只能按大小滚动,不能精确按天。

这表示:

  • 每天都会生成一个新日志文件%d{yyyy-MM-dd}

  • 在这一天中,如果日志文件超过 3KB,则会自动滚动新文件以.1.log,.2.log等结尾


方案2:logback-spring.xml 配置

src/main/resources/下创建logback-spring.xml

<?xml version="1.0" encoding="UTF-8"?> <configuration> <!-- 日志文件存放路径 --> <property name="LOG_PATH" value="logs"/> <!-- 控制台输出 --> <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender"> <encoder> <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern> </encoder> </appender> <!-- 按天滚动的文件输出 --> <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"> <!-- 当前正在写入的日志文件 --> <file>${LOG_PATH}/app.log</file> <!-- 滚动策略:按时间 --> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <!-- 每天生成一个新文件,文件名带日期 --> <fileNamePattern>${LOG_PATH}/app.%d{yyyy-MM-dd}.log</fileNamePattern> <!-- 保留 30 天的日志 --> <maxHistory>30</maxHistory> <!-- 总日志大小超过 10GB 时,删除旧的 --> <totalSizeCap>10GB</totalSizeCap> </rollingPolicy> <encoder> <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern> </encoder> </appender> <!-- 根日志级别 --> <root level="INFO"> <appender-ref ref="CONSOLE"/> <appender-ref ref="FILE"/> </root> </configuration>

结果:

logs/ ├── app.log ← 今天的日志(正在写入) ├── app.2026-07-17.log ← 昨天的日志 ├── app.2026-07-16.log ← 前天的日志 └── ...

每天凌晨自动创建新文件,旧文件按日期归档。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询