
文章目录
-
- [Spring Boot 项目启动与运维完全指南](#Spring Boot 项目启动与运维完全指南)
- [------ 从编译打包到生产级部署的全流程详解](#—— 从编译打包到生产级部署的全流程详解)
- [📖 写在前面](#📖 写在前面)
- [第一章:Spring Boot 应用启动全览](#第一章:Spring Boot 应用启动全览)
-
- [1.1 项目结构回顾](#1.1 项目结构回顾)
- [1.2 Spring Boot 启动原理简述](#1.2 Spring Boot 启动原理简述)
- [1.3 可执行 JAR 包结构](#1.3 可执行 JAR 包结构)
- [第二章:Spring Boot 启动方式详解](#第二章:Spring Boot 启动方式详解)
-
- [2.1 方式一:标准启动(最常用)](#2.1 方式一:标准启动(最常用))
- [2.2 方式二:指定配置启动](#2.2 方式二:指定配置启动)
- [2.3 方式三:使用配置文件启动](#2.3 方式三:使用配置文件启动)
- [2.4 方式四:后台守护启动(生产环境)](#2.4 方式四:后台守护启动(生产环境))
- [2.5 方式五:使用系统服务(生产环境)](#2.5 方式五:使用系统服务(生产环境))
-
- [创建 Systemd 服务(Linux)](#创建 Systemd 服务(Linux))
- [创建 Launch Agent(macOS)](#创建 Launch Agent(macOS))
- 第三章:JVM参数调优详解
-
- [3.1 JVM内存模型](#3.1 JVM内存模型)
- [3.2 关键JVM参数](#3.2 关键JVM参数)
- [3.3 GC日志配置](#3.3 GC日志配置)
- [3.4 完整启动脚本示例](#3.4 完整启动脚本示例)
- 第四章:启动失败问题系统化排查
-
- [4.1 排查方法论](#4.1 排查方法论)
- [4.2 常见启动错误及解决方案](#4.2 常见启动错误及解决方案)
-
- [错误 1:端口被占用](#错误 1:端口被占用)
- [错误 2:数据库连接失败](#错误 2:数据库连接失败)
- [错误 3:Redis连接失败](#错误 3:Redis连接失败)
- [错误 4:OutOfMemoryError](#错误 4:OutOfMemoryError)
- [错误 5:类找不到](#错误 5:类找不到)
- [4.3 日志级别调整](#4.3 日志级别调整)
- [4.4 调试模式启动](#4.4 调试模式启动)
- 第五章:应用健康检查与监控
-
- [5.1 Spring Boot Actuator 配置](#5.1 Spring Boot Actuator 配置)
- [5.2 健康检查端点](#5.2 健康检查端点)
- [5.3 自定义健康检查](#5.3 自定义健康检查)
- [5.4 应用信息端点](#5.4 应用信息端点)
- 第六章:日志管理详解
-
- [6.1 Logback 配置](#6.1 Logback 配置)
- [6.2 日志切割与归档](#6.2 日志切割与归档)
- [6.3 日志查看与分析](#6.3 日志查看与分析)
- [6.4 日志级别动态调整](#6.4 日志级别动态调整)
- 第七章:性能优化与压测
- 第八章:运维场景实战
-
- [8.1 优雅关闭应用](#8.1 优雅关闭应用)
- [8.2 应用版本回滚](#8.2 应用版本回滚)
- [8.3 数据库迁移](#8.3 数据库迁移)
- [8.4 应用备份与恢复](#8.4 应用备份与恢复)
- [8.5 快速问题诊断命令集](#8.5 快速问题诊断命令集)
- 第九章:总结与最佳实践
-
- [9.1 启动运维清单](#9.1 启动运维清单)
Spring Boot 项目启动与运维完全指南
------ 从编译打包到生产级部署的全流程详解
📖 写在前面
在前两篇文章中,我们完成了:
- 第一篇:JDK 17 + Maven 3.9.8 的环境配置
- 第二篇:MySQL 8.0 + Redis 的安装与数据初始化
现在,所有准备工作已经就绪,是时候启动 Spring Boot 应用了。然而,java -jar 只是万里长征的第一步。应用启动过程中可能遇到各种问题:端口冲突、内存不足、配置文件错误、数据库连接池耗尽、日志配置不当......
本文将极其详细地讲解:
- Spring Boot 应用的多种启动方式与参数调优
- 启动失败问题的系统化排查方法论
- 应用健康检查与性能监控
- 生产级部署的最佳实践
- 常见运维场景的操作指南
第一章:Spring Boot 应用启动全览
1.1 项目结构回顾
~/Desktop/FeiChenERP/backend/
├── pom.xml # Maven项目配置
├── src/
│ ├── main/
│ │ ├── java/ # Java源代码
│ │ │ └── com/erp/
│ │ │ ├── OpenerpApplication.java # 启动类
│ │ │ ├── controller/ # 控制器层
│ │ │ ├── service/ # 业务逻辑层
│ │ │ ├── repository/ # 数据访问层
│ │ │ └── config/ # 配置类
│ │ ├── resources/
│ │ │ ├── application.yml # 主配置文件
│ │ │ ├── application-dev.yml # 开发环境配置
│ │ │ ├── application-prod.yml # 生产环境配置
│ │ │ ├── static/ # 静态资源
│ │ │ └── templates/ # 模板文件
│ │ └── webapp/ # Web资源(可选)
│ └── test/ # 测试代码
└── target/ # 编译输出目录
├── classes/ # 编译后的class文件
├── openerp-backend-1.0.0.jar # 可执行JAR包
└── openerp-backend-1.0.0.jar.original # 原始JAR(不含依赖)
1.2 Spring Boot 启动原理简述
Spring Boot 应用启动的核心流程:
java -jar app.jar
↓
加载 META-INF/MANIFEST.MF
↓
定位 Main-Class: org.springframework.boot.loader.JarLauncher
↓
JarLauncher 启动嵌入式 Tomcat
↓
加载 Spring 容器配置
↓
执行 AutoConfiguration(自动配置)
↓
初始化 DataSource、Redis、JPA 等组件
↓
执行 CommandLineRunner / ApplicationRunner
↓
应用启动完成,监听端口(默认 8080)
1.3 可执行 JAR 包结构
Spring Boot 生成的 JAR 包是一个 "Fat JAR"(胖JAR),包含了所有依赖:
bash
# 查看JAR包内容
jar tf target/openerp-backend-1.0.0.jar | head -30
# 输出结构:
# META-INF/
# META-INF/MANIFEST.MF # 清单文件,定义启动类
# BOOT-INF/
# BOOT-INF/classes/ # 应用编译后的class文件
# BOOT-INF/lib/ # 所有依赖JAR包(可能有几十到上百个)
# org/
# org/springframework/boot/loader/ # Spring Boot类加载器
JAR包大小分析:
bash
# 查看JAR包大小
ls -lh target/openerp-backend-1.0.0.jar
# 分析JAR包组成
unzip -l target/openerp-backend-1.0.0.jar | sort -nr -k3 | head -20
# 可以找出最大的依赖包
第二章:Spring Boot 启动方式详解
2.1 方式一:标准启动(最常用)
bash
cd ~/Desktop/FeiChenERP/backend
java -jar target/openerp-backend-1.0.0.jar
启动日志解读:
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v3.2.5)
↑ Spring Boot 版本
2026-07-26 10:30:15.123 INFO 12345 --- [ main] com.erp.OpenerpApplication : Starting OpenerpApplication v1.0.0 using Java 17.0.11 with PID 12345 (/Users/xxx/Desktop/FeiChenERP/backend/target/openerp-backend-1.0.0.jar started by xxx in /Users/xxx/Desktop/FeiChenERP/backend)
↑ 启动信息:应用名、版本、Java版本、进程ID、JAR路径、工作目录
2026-07-26 10:30:15.456 INFO 12345 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port 8080 (http)
↑ 嵌入式Tomcat初始化,监听8080端口
2026-07-26 10:30:15.789 INFO 12345 --- [ main] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Starting...
2026-07-26 10:30:16.123 INFO 12345 --- [ main] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Start completed.
↑ 数据库连接池初始化
2026-07-26 10:30:16.456 INFO 12345 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port 8080 (http) with context path ''
↑ Tomcat启动完成,上下文路径为空(即根路径)
2026-07-26 10:30:16.789 INFO 12345 --- [ main] com.erp.OpenerpApplication : Started OpenerpApplication in 3.456 seconds (process running for 4.123)
↑ 应用启动完成,耗时3.456秒
2.2 方式二:指定配置启动
bash
# 覆盖单个配置项
java -jar target/openerp-backend-1.0.0.jar \
--server.port=9090 \
--spring.datasource.url="jdbc:mysql://localhost:3306/openerp?useSSL=false" \
--spring.datasource.password=123456 \
--spring.sql.init.mode=never
常用覆盖参数:
| 参数 | 默认值 | 说明 |
|---|---|---|
--server.port |
8080 | HTTP服务端口 |
--server.context-path |
空 | 应用上下文路径 |
--spring.profiles.active |
default | 激活的配置文件 |
--spring.datasource.url |
配置文件中 | 数据库连接URL |
--spring.datasource.username |
配置文件中 | 数据库用户名 |
--spring.datasource.password |
配置文件中 | 数据库密码 |
--spring.redis.host |
localhost | Redis主机 |
--spring.redis.port |
6379 | Redis端口 |
--logging.level.root |
INFO | 日志级别 |
--spring.sql.init.mode |
embedded | SQL初始化模式 |
2.3 方式三:使用配置文件启动
bash
# 使用外部的application.yml
java -jar target/openerp-backend-1.0.0.jar \
--spring.config.location=file:/path/to/application.yml
# 使用环境特定的配置文件
java -jar target/openerp-backend-1.0.0.jar \
--spring.profiles.active=prod \
--spring.config.additional-location=file:/etc/erp/config/
配置文件加载优先级(从高到低):
- 命令行参数
- 操作系统环境变量(
SPRING_APPLICATION_JSON) - JAR包外的
application-{profile}.properties/yml - JAR包内的
application-{profile}.properties/yml - JAR包外的
application.properties/yml - JAR包内的
application.properties/yml
2.4 方式四:后台守护启动(生产环境)
bash
# 使用nohup
nohup java -jar target/openerp-backend-1.0.0.jar \
--spring.profiles.active=prod \
> logs/app.log 2>&1 &
# 记录进程ID
echo $! > app.pid
# 查看日志
tail -f logs/app.log
# 停止应用
kill $(cat app.pid)
nohup 参数说明:
| 符号 | 含义 |
|---|---|
nohup |
忽略挂断信号(终端关闭不影响进程) |
> logs/app.log |
标准输出重定向到日志文件 |
2>&1 |
标准错误重定向到标准输出(也写入日志) |
& |
后台运行 |
$! |
最后一个后台进程的PID |
2.5 方式五:使用系统服务(生产环境)
创建 Systemd 服务(Linux)
ini
# /etc/systemd/system/openerp.service
[Unit]
Description=OpenERP Backend Application
After=network.target mysql.service redis.service
[Service]
Type=simple
User=erpuser
WorkingDirectory=/opt/openerp/backend
ExecStart=/usr/bin/java -jar /opt/openerp/backend/openerp-backend-1.0.0.jar --spring.profiles.active=prod
Restart=always
RestartSec=10
StandardOutput=journal
StandardError=journal
Environment="JAVA_HOME=/usr/lib/jvm/java-17"
[Install]
WantedBy=multi-user.target
bash
# 启动服务
sudo systemctl start openerp
# 设置开机自启动
sudo systemctl enable openerp
# 查看状态
sudo systemctl status openerp
# 查看日志
sudo journalctl -u openerp -f
创建 Launch Agent(macOS)
xml
<!-- ~/Library/LaunchAgents/com.erp.openerp.plist -->
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>com.erp.openerp</string>
<key>ProgramArguments</key>
<array>
<string>/usr/bin/java</string>
<string>-jar</string>
<string>/Users/xxx/Desktop/FeiChenERP/backend/openerp-backend-1.0.0.jar</string>
<string>--spring.profiles.active=prod</string>
<string>--server.port=8080</string>
</array>
<key>RunAtLoad</key>
<true/>
<key>KeepAlive</key>
<true/>
<key>WorkingDirectory</key>
<string>/Users/xxx/Desktop/FeiChenERP/backend</string>
<key>StandardOutPath</key>
<string>/Users/xxx/Desktop/FeiChenERP/backend/logs/app.log</string>
<key>StandardErrorPath</key>
<string>/Users/xxx/Desktop/FeiChenERP/backend/logs/error.log</string>
</dict>
</plist>
第三章:JVM参数调优详解
3.1 JVM内存模型
┌─────────────────────────────────────────────────────────────┐
│ JVM 内存 │
├─────────────────────────────────────────────────────────────┤
│ ┌─────────────────────┐ ┌─────────────────────────────┐ │
│ │ 堆内存 (Heap) │ │ 非堆内存 (Non-Heap) │ │
│ │ ┌──────┐ ┌──────┐ │ │ ┌──────────┐ ┌──────────┐ │ │
│ │ │Young │ │ Old │ │ │ │ Metaspace│ │ Code │ │ │
│ │ │Gen │ │ Gen │ │ │ │ │ │ Cache │ │ │
│ │ └──────┘ └──────┘ │ │ └──────────┘ └──────────┘ │ │
│ └─────────────────────┘ └─────────────────────────────┘ │
│ ↑ 对象实例 ↑ 类元数据、JIT编译代码 │
│ ↑ 由GC管理 ↑ 无GC或弱GC │
└─────────────────────────────────────────────────────────────┘
3.2 关键JVM参数
bash
java -Xms2g -Xmx2g -XX:MetaspaceSize=256m -XX:MaxMetaspaceSize=512m \
-XX:+UseG1GC -XX:MaxGCPauseMillis=200 \
-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/var/log/erp/dump.hprof \
-jar target/openerp-backend-1.0.0.jar
参数详解:
| 参数 | 说明 | 推荐值 |
|---|---|---|
-Xms |
初始堆内存大小 | 与 -Xmx 相同,避免动态调整 |
-Xmx |
最大堆内存大小 | 物理内存的60-70%(如8GB内存设4-5GB) |
-Xmn |
年轻代大小 | 堆大小的1/3 |
-XX:MetaspaceSize |
元空间初始大小 | 256m |
-XX:MaxMetaspaceSize |
元空间最大大小 | 512m |
-XX:+UseG1GC |
使用G1垃圾回收器 | Java 9+默认,适合大堆内存 |
-XX:MaxGCPauseMillis |
GC最大暂停时间目标 | 200ms |
-XX:+HeapDumpOnOutOfMemoryError |
OOM时导出堆转储 | 建议开启 |
-XX:HeapDumpPath |
堆转储文件路径 | 指定目录 |
3.3 GC日志配置
bash
java -jar target/openerp-backend-1.0.0.jar \
-Xlog:gc*:file=logs/gc.log:time,uptime,level,tags:filecount=5,filesize=50m \
-XX:+PrintGCDetails \
-XX:+PrintGCDateStamps
3.4 完整启动脚本示例
bash
#!/bin/bash
# start.sh - 生产环境启动脚本
APP_NAME="openerp-backend"
APP_VERSION="1.0.0"
JAR_FILE="target/${APP_NAME}-${APP_VERSION}.jar"
LOG_DIR="logs"
PID_FILE="${APP_NAME}.pid"
# JVM参数
JAVA_OPTS="-Xms2g -Xmx2g -XX:MetaspaceSize=256m -XX:MaxMetaspaceSize=512m"
JAVA_OPTS="${JAVA_OPTS} -XX:+UseG1GC -XX:MaxGCPauseMillis=200"
JAVA_OPTS="${JAVA_OPTS} -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=${LOG_DIR}/heapdump.hprof"
JAVA_OPTS="${JAVA_OPTS} -XX:+PrintGCDetails -XX:+PrintGCDateStamps -Xloggc:${LOG_DIR}/gc.log"
# Spring参数
SPRING_OPTS="--spring.profiles.active=prod"
SPRING_OPTS="${SPRING_OPTS} --spring.sql.init.mode=never"
start() {
echo "Starting ${APP_NAME}..."
mkdir -p ${LOG_DIR}
nohup java ${JAVA_OPTS} -jar ${JAR_FILE} ${SPRING_OPTS} \
> ${LOG_DIR}/app.log 2>&1 &
echo $! > ${PID_FILE}
echo "Started with PID $(cat ${PID_FILE})"
}
stop() {
echo "Stopping ${APP_NAME}..."
if [ -f ${PID_FILE} ]; then
kill $(cat ${PID_FILE})
rm ${PID_FILE}
echo "Stopped"
else
echo "PID file not found"
fi
}
status() {
if [ -f ${PID_FILE} ]; then
PID=$(cat ${PID_FILE})
if ps -p ${PID} > /dev/null 2>&1; then
echo "${APP_NAME} is running with PID ${PID}"
else
echo "${APP_NAME} is not running (stale PID file)"
fi
else
echo "${APP_NAME} is not running"
fi
}
case "$1" in
start) start ;;
stop) stop ;;
restart) stop && sleep 2 && start ;;
status) status ;;
*) echo "Usage: $0 {start|stop|restart|status}" ;;
esac
第四章:启动失败问题系统化排查
4.1 排查方法论
启动失败
↓
查看日志(最快信息源)
↓
识别错误类型
↓
├── 数据库相关 ──→ 检查MySQL连接
├── Redis相关 ──→ 检查Redis连接
├── 端口冲突 ──→ 检查端口占用
├── 内存不足 ──→ 调整JVM参数
├── 配置错误 ──→ 检查配置文件
├── 类加载失败 ──→ 检查依赖冲突
└── 其他异常 ──→ 分析具体堆栈
4.2 常见启动错误及解决方案
错误 1:端口被占用
APPLICATION FAILED TO START
***************************
Description:
Web server failed to start. Port 8080 was already in use.
Action:
Identify and stop the process that's listening on port 8080 or configure this application to listen on another port.
解决方案:
bash
# 1. 查找占用端口的进程
lsof -i :8080
sudo netstat -anp | grep 8080 # Linux
# 2. 结束进程
kill -9 [PID]
# 3. 或修改应用端口
java -jar app.jar --server.port=9090
# 4. 或使用系统属性
java -Dserver.port=9090 -jar app.jar
错误 2:数据库连接失败
APPLICATION FAILED TO START
***************************
Description:
Failed to configure a DataSource: 'url' attribute is not specified and no embedded datasource could be configured.
Reason: Failed to determine a suitable driver class
原因:Spring Boot 无法连接到配置的数据库。
解决方案:
bash
# 1. 检查MySQL是否运行
ps aux | grep mysql
mysqladmin -u root -p status
# 2. 检查配置文件
cat src/main/resources/application.yml | grep -A5 "datasource"
# 3. 手动测试数据库连接
mysql -u root -p123456 -h localhost -P 3306 -e "SELECT 1"
# 4. 检查数据库是否存在
mysql -u root -p123456 -e "SHOW DATABASES LIKE 'openerp'"
# 5. 启动时指定数据库配置
java -jar app.jar \
--spring.datasource.url="jdbc:mysql://localhost:3306/openerp?useSSL=false&allowPublicKeyRetrieval=true" \
--spring.datasource.username=root \
--spring.datasource.password=123456
错误 3:Redis连接失败
Redis connection failed: Connection refused: localhost/127.0.0.1:6379
解决方案:
bash
# 1. 启动Redis
brew services start redis
# 或
redis-server --daemonize yes
# 2. 测试连接
redis-cli ping
# 3. 如果应用强制要求Redis,暂时禁用Redis配置
java -jar app.jar --spring.data.redis.repositories.enabled=false
错误 4:OutOfMemoryError
java.lang.OutOfMemoryError: Java heap space
解决方案:
bash
# 增加堆内存
java -Xmx2g -Xms2g -jar app.jar
# 增加元空间大小
java -XX:MaxMetaspaceSize=512m -jar app.jar
# 启用G1GC优化
java -XX:+UseG1GC -XX:MaxGCPauseMillis=200 -jar app.jar
错误 5:类找不到
java.lang.ClassNotFoundException: org.springframework.boot.SpringApplication
原因:JAR包不完整或损坏。
解决方案:
bash
# 1. 重新构建
mvn clean package -DskipTests
# 2. 检查JAR包完整性
jar tf target/openerp-backend-1.0.0.jar | grep SpringApplication
# 3. 检查Maven依赖
mvn dependency:tree
# 4. 清理本地仓库(修复损坏依赖)
rm -rf ~/.m2/repository/org/springframework/boot
mvn clean package -DskipTests
4.3 日志级别调整
bash
# 启动时调整日志级别
java -jar app.jar \
--logging.level.root=DEBUG \
--logging.level.org.springframework.boot=DEBUG \
--logging.level.com.erp=DEBUG
# 在application.yml中配置
logging:
level:
root: INFO
com.erp: DEBUG
org.springframework.boot: INFO
org.hibernate: DEBUG
com.zaxxer.hikari: DEBUG
4.4 调试模式启动
bash
# 远程调试(端口 5005)
java -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005 \
-jar app.jar
# IDEA中连接:Run → Debug → Remote JVM Debug
# Host: localhost, Port: 5005
第五章:应用健康检查与监控
5.1 Spring Boot Actuator 配置
Spring Boot Actuator 提供了生产级的监控和管理端点。
yaml
# application.yml
management:
endpoints:
web:
exposure:
include: health,info,metrics,env,configprops
base-path: /actuator
endpoint:
health:
show-details: always
show-components: always
info:
env:
enabled: true
info:
app:
name: ${spring.application.name}
version: @project.version@
description: @project.description@
build:
artifact: @project.artifactId@
time: @maven.build.timestamp@
5.2 健康检查端点
bash
# 基础健康检查
curl http://localhost:8080/actuator/health
# 响应示例
{
"status": "UP",
"components": {
"db": {
"status": "UP",
"details": {
"database": "MySQL",
"validationQuery": "isValid()"
}
},
"redis": {
"status": "UP",
"details": {
"version": "7.2.4"
}
},
"diskSpace": {
"status": "UP",
"details": {
"total": 500068036608,
"free": 234567890123,
"threshold": 10485760
}
}
}
}
# 详细健康信息(需要 management.endpoint.health.show-details=always)
curl http://localhost:8080/actuator/health | jq .
5.3 自定义健康检查
java
@Component
public class CustomHealthIndicator implements HealthIndicator {
@Override
public Health health() {
boolean isHealthy = checkExternalService();
if (isHealthy) {
return Health.up()
.withDetail("service", "External API")
.withDetail("status", "Available")
.build();
}
return Health.down()
.withDetail("service", "External API")
.withDetail("status", "Unavailable")
.withDetail("error", "Connection timeout")
.build();
}
}
5.4 应用信息端点
bash
# 查看应用信息
curl http://localhost:8080/actuator/info
# 查看指标
curl http://localhost:8080/actuator/metrics
# 查看特定指标(如内存使用)
curl http://localhost:8080/actuator/metrics/jvm.memory.used
# 查看线程信息
curl http://localhost:8080/actuator/threaddump
# 查看环境属性
curl http://localhost:8080/actuator/env
第六章:日志管理详解
6.1 Logback 配置
创建 src/main/resources/logback-spring.xml:
xml
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<!-- 控制台输出 -->
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
<charset>UTF-8</charset>
</encoder>
</appender>
<!-- 文件输出 - 所有日志 -->
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>logs/openerp.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>logs/openerp.%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>100MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
<maxHistory>30</maxHistory>
</rollingPolicy>
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
<charset>UTF-8</charset>
</encoder>
</appender>
<!-- 错误日志单独输出 -->
<appender name="ERROR_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>logs/error.log</file>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>ERROR</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>logs/error.%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<maxHistory>30</maxHistory>
</rollingPolicy>
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
<charset>UTF-8</charset>
</encoder>
</appender>
<!-- 异步日志(提高性能) -->
<appender name="ASYNC" class="ch.qos.logback.classic.AsyncAppender">
<appender-ref ref="FILE"/>
<queueSize>1024</queueSize>
<discardingThreshold>0</discardingThreshold>
</appender>
<!-- 根日志级别 -->
<root level="INFO">
<appender-ref ref="CONSOLE"/>
<appender-ref ref="ASYNC"/>
<appender-ref ref="ERROR_FILE"/>
</root>
<!-- 特定包的日志级别 -->
<logger name="com.erp" level="DEBUG"/>
<logger name="org.springframework.web" level="INFO"/>
<logger name="org.hibernate" level="INFO"/>
<logger name="com.zaxxer.hikari" level="INFO"/>
</configuration>
6.2 日志切割与归档
yaml
# application.yml 日志配置
logging:
file:
name: logs/openerp.log
path: logs/
logback:
rollingpolicy:
max-file-size: 100MB
max-history: 30
total-size-cap: 10GB
clean-history-on-start: true
6.3 日志查看与分析
bash
# 实时查看日志
tail -f logs/app.log
# 查看最近100行
tail -100 logs/app.log
# 搜索错误
grep ERROR logs/app.log
# 统计错误数量
grep -c ERROR logs/app.log
# 查看特定时间段的日志
sed -n '/2026-07-26 10:/,/2026-07-26 11:/p' logs/app.log
# 使用less查看大日志
less logs/app.log
# 在less中: / 搜索, G 跳到末尾, g 跳到开头
6.4 日志级别动态调整
bash
# 通过Actuator调整日志级别(需要开启)
curl -X POST http://localhost:8080/actuator/loggers/com.erp \
-H "Content-Type: application/json" \
-d '{"configuredLevel": "DEBUG"}'
# 查看当前日志级别
curl http://localhost:8080/actuator/loggers/com.erp
第七章:性能优化与压测
7.1 应用性能调优
数据库连接池优化
yaml
spring:
datasource:
hikari:
# 连接池大小
maximum-pool-size: 20
minimum-idle: 5
# 连接超时
connection-timeout: 30000
idle-timeout: 600000
max-lifetime: 1800000
# 验证查询
connection-test-query: SELECT 1
validation-timeout: 3000
线程池优化
yaml
server:
tomcat:
threads:
max: 200
min-spare: 10
max-connections: 10000
connection-timeout: 20000
accept-count: 100
7.2 压力测试
bash
# 使用 Apache Bench (ab)
# 安装
brew install httpd # macOS
sudo apt install apache2-utils # Ubuntu
# 基础压测
ab -n 1000 -c 10 http://localhost:8080/api/health
# 参数说明
# -n: 总请求数
# -c: 并发数
# -H: 添加请求头
# -p: POST数据文件
# -T: Content-Type
# 使用 wrk (更强大)
# 安装
brew install wrk
# 压测
wrk -t 4 -c 100 -d 30s http://localhost:8080/api/users
# -t: 线程数
# -c: 连接数
# -d: 持续时间
7.3 性能监控指标
bash
# 查看JVM内存使用
curl http://localhost:8080/actuator/metrics/jvm.memory.used
# 查看GC情况
curl http://localhost:8080/actuator/metrics/jvm.gc.pause
# 查看请求QPS
curl http://localhost:8080/actuator/metrics/http.server.requests
# 查看数据库连接池
curl http://localhost:8080/actuator/metrics/hikaricp.connections
第八章:运维场景实战
8.1 优雅关闭应用
Spring Boot 支持优雅关闭:
yaml
server:
shutdown: graceful
spring:
lifecycle:
timeout-per-shutdown-phase: 30s
bash
# 发送SIGTERM信号触发优雅关闭
kill -15 $(cat app.pid)
# 或
pkill -15 -f openerp-backend
8.2 应用版本回滚
bash
# 保留多个版本
ls -la releases/
# openerp-backend-1.0.0.jar
# openerp-backend-1.0.1.jar
# openerp-backend-1.0.2.jar
# 创建符号链接
ln -sf releases/openerp-backend-1.0.1.jar current/openerp-backend.jar
# 重启应用
./start.sh restart
8.3 数据库迁移
bash
# 使用Flyway或Liquibase进行版本化数据库迁移
# 或手动执行SQL脚本
mysql -u root -p123456 openerp < migrations/V1.1__add_new_table.sql
# 验证迁移结果
mysql -u root -p123456 openerp -e "SHOW TABLES;"
8.4 应用备份与恢复
bash
# 备份JAR包
cp target/openerp-backend-1.0.0.jar backups/openerp-backend-$(date +%Y%m%d).jar
# 备份配置文件
cp src/main/resources/application.yml backups/application-$(date +%Y%m%d).yml
# 备份数据库
mysqldump -u root -p123456 openerp > backups/openerp-$(date +%Y%m%d).sql
# 恢复数据库
mysql -u root -p123456 openerp < backups/openerp-20260726.sql
8.5 快速问题诊断命令集
bash
# 一键检查应用状态
echo "=== 应用状态 ===" && ps aux | grep openerp | grep -v grep && \
echo "=== 端口监听 ===" && lsof -i :8080 && \
echo "=== MySQL状态 ===" && mysqladmin -u root -p123456 status && \
echo "=== Redis状态 ===" && redis-cli ping && \
echo "=== 健康检查 ===" && curl -s http://localhost:8080/actuator/health | jq .status && \
echo "=== 最近错误 ===" && tail -20 logs/app.log | grep ERROR
第九章:总结与最佳实践
9.1 启动运维清单
| 检查项 | 命令/方法 | 预期结果 |
|---|---|---|
| 应用是否运行 | `ps aux | grep app.jar` |
| 端口是否监听 | `lsof - |
您好,我是肥晨。
欢迎关注我获取前端/AI学习资源,日常分享技术变革,生存法则;行业内幕,洞察先机。