1. 为什么选择Ubuntu部署SpringBoot应用?
作为一名长期在Linux环境下工作的Java开发者,我始终认为Ubuntu是最适合SpringBoot应用部署的操作系统之一。这不仅仅是因为Ubuntu在服务器领域的广泛使用,更因为它与Java生态的完美契合度。根据2023年Stack Overflow开发者调查,超过35%的专业开发者选择Ubuntu作为主要开发环境,而其中Java开发者占比高达42%。
Ubuntu LTS版本(如22.04)提供了长达5年的安全更新支持,这对于生产环境至关重要。我在实际项目中发现,相比其他Linux发行版,Ubuntu对Java应用的支持更为友好:
- 官方维护的OpenJDK软件包更新及时
- 系统服务管理工具systemd与Java应用集成良好
- 完善的防火墙和网络配置工具
- 丰富的监控和日志管理工具链
提示:虽然生产环境推荐使用服务器版Ubuntu,但开发测试阶段使用桌面版也完全可行。我经常在Ubuntu Desktop上直接运行SpringBoot应用进行调试。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 环境准备与基础配置
2.1 Java环境安装最佳实践
在Ubuntu上安装Java看似简单,但其中有不少细节需要注意。我推荐使用SDKMAN!来管理Java版本,这是我在多个生产项目中验证过的最佳方案:
bash复制# 安装SDKMAN!
curl -s "https://get.sdkman.io" | bash
source "$HOME/.sdkman/bin/sdkman-init.sh"
# 安装指定版本JDK
sdk install java 17.0.8-tem
为什么选择SDKMAN!而不是直接apt安装?原因有三:
- 可以同时管理多个JDK版本,方便不同项目切换
- 避免系统级Java安装可能导致的依赖冲突
- 支持所有主流JDK发行版(Temurin、Corretto等)
验证安装时,不要只运行java -version,我建议执行完整检查:
bash复制# 检查JAVA_HOME设置
echo $JAVA_HOME
# 验证关键工具链
which java
which javac
which jps
2.2 系统优化配置
很多教程会跳过系统调优步骤,但这恰恰是影响应用性能的关键。以下是我总结的必做配置:
文件描述符限制调整:
bash复制# 查看当前限制
ulimit -n
# 永久修改配置
echo "* soft nofile 65535" | sudo tee -a /etc/security/limits.conf
echo "* hard nofile 65535" | sudo tee -a /etc/security/limits.conf
交换空间优化(特别是内存小于4GB的服务器):
bash复制# 查看当前swappiness值
cat /proc/sys/vm/swappiness
# 建议设置为10(默认60)
sudo sysctl vm.swappiness=10
时区配置(避免日志时间错乱):
bash复制sudo timedatectl set-timezone Asia/Shanghai
3. SpringBoot应用打包与传输
3.1 生产级打包技巧
使用Maven打包时,我强烈建议添加以下配置到pom.xml:
xml复制<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<executable>true</executable> <!-- 关键配置 -->
<layers>
<enabled>true</enabled> <!-- 启用分层优化 -->
</layers>
</configuration>
</plugin>
</plugins>
</build>
executable=true这个配置让JAR包可以直接作为系统服务运行,而分层打包则能显著提升Docker镜像构建效率(即使你不使用Docker)。
打包命令也有讲究:
bash复制# 带分类器的打包(推荐)
mvn clean package -DskipTests -Dspring-boot.repackage.classifier=exec
这样会生成两个JAR文件:原始包和可执行包,便于版本管理。
3.2 安全传输方案
将JAR包传到服务器有多种方式,但安全性常被忽视。我常用的方案是:
- 使用rsync通过SSH传输:
bash复制rsync -avz -e "ssh -p 22" target/your-app.jar user@server:/opt/app/
- 配合SSH密钥认证(比密码更安全):
bash复制# 本地生成密钥对
ssh-keygen -t ed25519
# 将公钥上传到服务器
ssh-copy-id -i ~/.ssh/id_ed25519.pub user@server
- 传输后验证文件完整性:
bash复制# 本地生成校验和
sha256sum target/your-app.jar
# 服务器端验证
sha256sum /opt/app/your-app.jar
4. 生产环境部署方案
4.1 Systemd服务配置
这是我最推荐的SpringBoot应用管理方式。创建/etc/systemd/system/yourapp.service文件:
ini复制[Unit]
Description=Your SpringBoot Application
After=syslog.target network.target
[Service]
User=appuser
Group=appgroup
WorkingDirectory=/opt/app
ExecStart=/opt/app/your-app.jar
SuccessExitStatus=143
# 重要安全配置
PrivateTmp=true
ProtectSystem=full
NoNewPrivileges=true
# JVM调优参数
Environment="JAVA_OPTS=-Xms512m -Xmx1024m -XX:MaxRAMPercentage=75.0"
Restart=always
RestartSec=10
[Install]
WantedBy=multi-user.target
关键配置说明:
User/Group:不要使用root运行应用WorkingDirectory:确保日志等文件写入正确位置Environment:JVM参数在此设置而非启动脚本Restart:实现故障自动恢复
启用服务:
bash复制sudo systemctl daemon-reload
sudo systemctl enable yourapp
sudo systemctl start yourapp
4.2 日志管理实战
默认的SpringBoot日志配置不适合生产环境。我的方案:
- 创建
logback-spring.xml配置文件:
xml复制<configuration>
<property name="LOG_PATH" value="/var/log/yourapp"/>
<property name="LOG_FILE" value="${LOG_PATH}/application.log"/>
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_FILE}</file>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>${LOG_PATH}/application.%d{yyyy-MM-dd}.%i.log.gz</fileNamePattern>
<maxFileSize>50MB</maxFileSize>
<maxHistory>30</maxHistory>
<totalSizeCap>5GB</totalSizeCap>
</rollingPolicy>
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<!-- 生产环境只记录WARN以上级别 -->
<root level="WARN">
<appender-ref ref="FILE"/>
</root>
</configuration>
- 配置logrotate实现日志轮转:
bash复制# /etc/logrotate.d/yourapp
/var/log/yourapp/*.log {
daily
missingok
rotate 30
compress
delaycompress
notifempty
create 640 appuser appgroup
sharedscripts
postrotate
systemctl kill -s HUP yourapp.service
endscript
}
5. 高级部署技巧
5.1 蓝绿部署实现
对于关键业务系统,我采用蓝绿部署方案:
- 准备两个相同的目录结构:
code复制/opt/app/
├── blue/
│ ├── yourapp.jar
│ └── config/
└── green/
├── yourapp.jar
└── config/
- 使用符号链接指向当前活跃版本:
bash复制ln -sfn /opt/app/blue /opt/app/current
- 更新服务配置指向符号链接:
ini复制ExecStart=/opt/app/current/yourapp.jar
WorkingDirectory=/opt/app/current
- 切换版本时:
bash复制# 部署新版本到非活跃目录(如green)
# 测试通过后切换链接
ln -sfn /opt/app/green /opt/app/current
systemctl restart yourapp
5.2 健康检查与监控
SpringBoot Actuator是必备的监控组件。安全配置建议:
yaml复制management:
endpoint:
health:
probes:
enabled: true # 启用K8s风格的探针
show-details: always
endpoints:
web:
exposure:
include: health,info,metrics
server:
port: 8081 # 与管理端口分离
配合Prometheus监控的配置:
xml复制<!-- pom.xml添加依赖 -->
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-registry-prometheus</artifactId>
</dependency>
对应的systemd服务可以添加健康检查:
ini复制ExecStartPre=/usr/bin/curl -sf http://localhost:8081/health/liveness
TimeoutStartSec=300 # 适当延长启动超时
6. 安全加固措施
6.1 文件系统权限
正确的权限设置可以阻止大部分入侵尝试:
bash复制# 应用目录权限
sudo chown -R appuser:appgroup /opt/app
sudo chmod 750 /opt/app
find /opt/app -type d -exec chmod 750 {} \;
find /opt/app -type f -exec chmod 640 {} \;
# 日志目录
sudo mkdir -p /var/log/yourapp
sudo chown appuser:appgroup /var/log/yourapp
sudo chmod 755 /var/log/yourapp
6.2 网络层防护
使用UFW防火墙的基础配置:
bash复制sudo ufw allow 22/tcp # SSH
sudo ufw allow 80/tcp # HTTP
sudo ufw allow 443/tcp # HTTPS
sudo ufw enable
对于直接暴露的SpringBoot应用(不推荐),至少应该:
bash复制# 限制只允许特定IP访问管理端口
sudo ufw allow from 192.168.1.0/24 to any port 8081
6.3 JVM安全参数
在生产环境启动参数中必须包含:
bash复制-Djava.security.egd=file:/dev/./urandom
-Dfile.encoding=UTF-8
-XX:+UseContainerSupport
-XX:+EnableJVMCI
-XX:+TieredCompilation
-XX:+UseG1GC
7. 性能调优实战
7.1 JVM内存配置
根据我的经验,内存配置应该遵循以下原则:
- 容器环境下使用百分比配置:
bash复制-XX:MaxRAMPercentage=75.0
-XX:InitialRAMPercentage=50.0
- 物理服务器上根据系统内存调整:
bash复制# 4GB内存服务器示例
-Xms1g
-Xmx3g
-XX:MetaspaceSize=256m
-XX:MaxMetaspaceSize=512m
7.2 GC调优
G1GC的推荐配置:
bash复制-XX:+UseG1GC
-XX:MaxGCPauseMillis=200
-XX:InitiatingHeapOccupancyPercent=45
-XX:G1ReservePercent=15
-XX:ParallelGCThreads=4
-XX:ConcGCThreads=2
关键指标监控命令:
bash复制# 查看GC情况
jstat -gcutil <pid> 1000 5
# 生成堆转储(OOM时自动生成)
-XX:+HeapDumpOnOutOfMemoryError
-XX:HeapDumpPath=/path/to/dumps
7.3 线程池优化
Tomcat连接器配置示例(application.yml):
yaml复制server:
tomcat:
threads:
max: 200
min-spare: 20
connection-timeout: 5000
accept-count: 100
max-connections: 10000
监控线程状态:
bash复制# 查看线程数变化
jcmd <pid> Thread.print
8. 常见问题排查
8.1 启动失败排查流程
我总结的标准排查步骤:
- 检查服务状态:
bash复制systemctl status yourapp
journalctl -u yourapp -n 50 --no-pager
- 直接运行JAR定位问题:
bash复制java -jar /opt/app/yourapp.jar
- 检查端口冲突:
bash复制ss -tulnp | grep java
lsof -i :8080
- 验证配置文件:
bash复制# 检查YAML语法
yamllint application.yml
# 查看生效配置
java -jar yourapp.jar --debug
8.2 内存泄漏诊断
我的诊断工具箱:
- 快速查看内存状态:
bash复制jcmd <pid> VM.native_memory summary
- 生成堆转储分析:
bash复制jmap -dump:live,format=b,file=heap.hprof <pid>
- 使用Eclipse Memory Analyzer分析:
bash复制# 下载MAT
wget https://download.eclipse.org/mat/1.11.0/rcp/MemoryAnalyzer-1.11.0.20210902-linux.gtk.x86_64.zip
8.3 性能瓶颈定位
Arthas工具实战示例:
bash复制# 安装Arthas
curl -O https://arthas.aliyun.com/arthas-boot.jar
java -jar arthas-boot.jar
# 常用命令
dashboard
thread -n 3
trace com.example.Class method
profiler start
9. 容器化部署方案
9.1 Docker基础部署
虽然标题聚焦传统部署,但容器化已成为主流。我的Dockerfile模板:
dockerfile复制FROM eclipse-temurin:17-jre-jammy
RUN useradd -ms /bin/bash appuser && \
mkdir -p /app && \
chown appuser:appuser /app
USER appuser
WORKDIR /app
COPY --chown=appuser:appuser target/your-app.jar /app/app.jar
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "app.jar"]
构建和运行命令:
bash复制docker build -t yourapp:1.0.0 .
docker run -d -p 8080:8080 --name yourapp \
-v /path/to/config:/app/config \
-e "JAVA_OPTS=-Xmx512m" \
yourapp:1.0.0
9.2 构建优化技巧
- 使用分层构建加速:
dockerfile复制# 第一阶段:构建
FROM eclipse-temurin:17-jdk-jammy as builder
WORKDIR /workspace
COPY . .
RUN ./mvnw package -DskipTests
# 第二阶段:运行
FROM eclipse-temurin:17-jre-jammy
COPY --from=builder /workspace/target/*.jar app.jar
ENTRYPOINT ["java","-jar","app.jar"]
- 使用JLink创建自定义运行时:
dockerfile复制FROM eclipse-temurin:17-jdk-jammy as jlink-build
RUN jlink --add-modules java.base,java.logging,java.management \
--strip-debug \
--no-man-pages \
--no-header-files \
--compress=2 \
--output /jre-minimal
FROM debian:bullseye-slim
COPY --from=jlink-build /jre-minimal /opt/jre
ENV PATH="/opt/jre/bin:${PATH}"
# 后续步骤同上
10. 持续部署实践
10.1 Jenkins自动化流水线
我的Jenkinsfile模板:
groovy复制pipeline {
agent any
environment {
DEPLOY_SERVER = 'user@server'
APP_DIR = '/opt/app'
}
stages {
stage('Build') {
steps {
sh 'mvn clean package -DskipTests'
}
}
stage('Test') {
steps {
sh 'mvn test'
}
}
stage('Deploy') {
steps {
sshagent(['deploy-key']) {
sh """
scp -o StrictHostKeyChecking=no target/*.jar ${DEPLOY_SERVER}:${APP_DIR}/new-version.jar
ssh ${DEPLOY_SERVER} "cd ${APP_DIR} && \
mv new-version.jar yourapp-${BUILD_NUMBER}.jar && \
ln -sfn yourapp-${BUILD_NUMBER}.jar current.jar && \
systemctl restart yourapp"
"""
}
}
}
}
}
10.2 健康检查与回滚
在部署脚本中添加健康检查:
bash复制# 部署后检查
HEALTH_CHECK=$(curl -s -o /dev/null -w "%{http_code}" http://localhost:8080/actuator/health)
if [ "$HEALTH_CHECK" != "200" ]; then
# 自动回滚到上一个版本
ssh ${DEPLOY_SERVER} "cd ${APP_DIR} && \
ln -sfn $(ls -t | grep -v current | head -2 | tail -1) current.jar && \
systemctl restart yourapp"
exit 1
fi
11. 备份与灾难恢复
11.1 应用备份策略
我采用的3-2-1备份方案:
- 本地备份脚本:
bash复制#!/bin/bash
BACKUP_DIR=/backups/yourapp
TIMESTAMP=$(date +%Y%m%d-%H%M%S)
# 停止服务
systemctl stop yourapp
# 创建备份
mkdir -p $BACKUP_DIR/$TIMESTAMP
cp -a /opt/app/current $BACKUP_DIR/$TIMESTAMP/app
cp -a /etc/systemd/system/yourapp.service $BACKUP_DIR/$TIMESTAMP/config
mysqldump -u user -p dbname > $BACKUP_DIR/$TIMESTAMP/db.sql
# 启动服务
systemctl start yourapp
# 保留最近7天备份
find $BACKUP_DIR -type d -mtime +7 -exec rm -rf {} \;
- 远程备份到S3:
bash复制aws s3 sync $BACKUP_DIR s3://your-bucket/backups/yourapp --delete
11.2 恢复演练流程
定期测试恢复流程至关重要:
- 准备干净环境
- 从备份恢复应用:
bash复制rsync -avz backup/app/ /opt/app/restored/
sudo cp backup/config/yourapp.service /etc/systemd/system/
sudo systemctl daemon-reload
- 恢复数据库:
bash复制mysql -u user -p dbname < backup/db.sql
- 启动服务并验证
12. 监控与告警体系
12.1 Prometheus监控配置
我的典型监控目标:
yaml复制# prometheus.yml
scrape_configs:
- job_name: 'springboot'
metrics_path: '/actuator/prometheus'
static_configs:
- targets: ['localhost:8080']
relabel_configs:
- source_labels: [__address__]
target_label: instance
replacement: 'yourapp-production'
关键监控指标:
- JVM内存使用率
- GC频率和耗时
- HTTP请求延迟和错误率
- 线程池使用情况
- 数据库连接池状态
12.2 Grafana仪表板
推荐使用4701标准仪表板:
bash复制# 导入SpringBoot监控仪表板
docker-compose exec grafana grafana-cli plugins install grafana-simple-json-datasource
配置告警规则示例:
yaml复制# alert.rules
groups:
- name: SpringBoot Alerts
rules:
- alert: HighHeapUsage
expr: sum(jvm_memory_used_bytes{area="heap"}) / sum(jvm_memory_max_bytes{area="heap"}) > 0.9
for: 5m
labels:
severity: critical
annotations:
summary: "High heap usage on {{ $labels.instance }}"
description: "Heap usage is {{ $value }}%"
13. 安全更新与维护
13.1 定期更新策略
我采用的滚动更新方案:
- 每周检查更新:
bash复制# 检查系统更新
sudo apt update
sudo apt list --upgradable
# 检查Java更新
sdk list java | grep -i installed
- 分阶段更新:
- 先在测试环境验证
- 然后预生产环境
- 最后生产环境滚动更新
- 更新后检查清单:
bash复制# 验证服务状态
systemctl status yourapp
# 检查日志异常
journalctl -u yourapp --since "1 hour ago" | grep -i error
# 功能测试
curl -I http://localhost:8080/health
13.2 依赖漏洞扫描
使用OWASP Dependency-Check:
bash复制# 安装工具
sudo apt install dependency-check
# 扫描项目
dependency-check --project "YourApp" --scan target/yourapp.jar --out reports/
集成到CI/CD流水线:
groovy复制stage('Security Scan') {
steps {
sh 'dependency-check --project "${JOB_NAME}" --scan "target/*.jar" --out "reports/"'
dependencyCheckPublisher pattern: 'reports/dependency-check-report.xml'
}
}
14. 性能基准测试
14.1 JMeter测试方案
我的标准测试计划结构:
- 线程组配置:
- 100并发用户
- 10秒启动时间
- 循环次数:永远
- 持续时间:300秒
- 关键采样器:
- HTTP请求默认值(设置基础URL)
- 登录请求(POST /login)
- 主要业务接口(GET /api/resources)
- 文件上传接口(POST /api/uploads)
- 监听器配置:
- 聚合报告
- 响应时间图
- 活动线程数
14.2 结果分析方法
重点关注指标:
| 指标 | 优秀值 | 可接受值 | 需优化值 |
|---|---|---|---|
| 平均响应时间 | <200ms | <500ms | >1s |
| 错误率 | 0% | <0.5% | >1% |
| 90%线 | <300ms | <800ms | >1.5s |
| 吞吐量 | >500rps | >200rps | <100rps |
压力测试命令示例:
bash复制jmeter -n -t TestPlan.jmx -l results.jtl -e -o report/
15. 多环境配置管理
15.1 Profile最佳实践
我的多环境配置方案:
- 目录结构:
code复制src/main/resources/
├── application.yml
├── application-dev.yml
├── application-prod.yml
└── application-test.yml
- 主配置(application.yml):
yaml复制spring:
profiles:
active: @activatedProperties@
config:
import:
- optional:classpath:application-${spring.profiles.active}.yml
- 构建时指定环境:
bash复制mvn package -Pprod
15.2 敏感信息处理
使用Jasypt加密配置:
- 添加依赖:
xml复制<dependency>
<groupId>com.github.ulisesbocchio</groupId>
<artifactId>jasypt-spring-boot-starter</artifactId>
<version>3.0.5</version>
</dependency>
- 加密敏感数据:
bash复制java -cp jasypt-1.9.3.jar org.jasypt.intf.cli.JasyptPBEStringEncryptionCLI \
input="dbpassword" password=secretkey algorithm=PBEWithMD5AndDES
- 配置文件中使用:
yaml复制datasource:
password: ENC(加密后的字符串)
- 启动时提供密钥:
bash复制java -jar yourapp.jar --jasypt.encryptor.password=secretkey
16. 数据库连接优化
16.1 HikariCP配置
生产级连接池配置:
yaml复制spring:
datasource:
hikari:
maximum-pool-size: 20
minimum-idle: 5
idle-timeout: 30000
max-lifetime: 1800000
connection-timeout: 5000
leak-detection-threshold: 5000
pool-name: SpringBootHikariCP
initialization-fail-timeout: 1
监控指标暴露:
java复制@Bean
public MeterRegistryCustomizer<MeterRegistry> metrics() {
return registry -> {
HikariDataSource dataSource = (HikariDataSource) registry;
dataSource.setMetricRegistry(registry);
};
}
16.2 连接泄漏排查
我常用的诊断方法:
- 启用泄漏检测:
yaml复制spring:
datasource:
hikari:
leak-detection-threshold: 5000 # 5秒
- 监控活跃连接:
bash复制# 查看数据库连接
SELECT * FROM pg_stat_activity WHERE usename = 'appuser';
# Hikari监控端点
curl http://localhost:8080/actuator/hikari
- 线程转储分析:
bash复制jstack <pid> > thread-dump.txt
grep -A 20 "HikariPool" thread-dump.txt
17. 缓存策略实施
17.1 Redis集成
SpringBoot与Redis的完美配合:
- 基础配置:
yaml复制spring:
cache:
type: redis
redis:
host: localhost
port: 6379
password: ${REDIS_PASSWORD}
timeout: 5000
lettuce:
pool:
max-active: 20
max-idle: 10
min-idle: 5
- 缓存注解使用:
java复制@Cacheable(value = "products", key = "#id")
public Product getProduct(Long id) {
// 数据库查询
}
@CacheEvict(value = "products", key = "#id")
public void updateProduct(Product product) {
// 更新逻辑
}
- 缓存监控:
bash复制redis-cli info stats | grep keyspace
redis-cli monitor
17.2 本地缓存选择
对于高频访问的只读数据,我推荐Caffeine:
java复制@Configuration
@EnableCaching
public class CacheConfig {
@Bean
public CaffeineCacheManager cacheManager() {
Caffeine<Object, Object> caffeine = Caffeine.newBuilder()
.maximumSize(1000)
.expireAfterWrite(10, TimeUnit.MINUTES)
.recordStats();
return new CaffeineCacheManager("localCache", caffeine);
}
}
性能对比:
| 缓存类型 | 读取速度 | 内存占用 | 适用场景 |
|---|---|---|---|
| Redis | 中 | 高 | 分布式缓存 |
| Caffeine | 极高 | 中 | 本地高频访问 |
| Ehcache | 高 | 高 | 复杂缓存策略 |
18. 消息队列集成
18.1 RabbitMQ实战
SpringBoot集成示例:
- 配置:
yaml复制spring:
rabbitmq:
host: localhost
port: 5672
username: guest
password: guest
listener:
simple:
concurrency: 5
max-concurrency: 10
prefetch: 50
- 生产者:
java复制@Autowired
private RabbitTemplate rabbitTemplate;
public void sendOrder(Order order) {
rabbitTemplate.convertAndSend("orders.exchange",
"orders.routingkey",
order,
message -> {
message.getMessageProperties()
.setDeliveryMode(MessageDeliveryMode.PERSISTENT);
return message;
});
}
- 消费者:
java复制@RabbitListener(queues = "orders.queue")
public void processOrder(Order order) {
// 处理订单
}
18.2 Kafka配置技巧
高吞吐量配置方案:
yaml复制spring:
kafka:
bootstrap-servers: localhost:9092
producer:
acks: all
retries: 3
batch-size: 16384
buffer-memory: 33554432
compression-type: snappy
consumer:
group-id: order-group
auto-offset-reset: earliest
enable-auto-commit: false
max-poll-records: 500
事务支持配置:
java复制@Bean
public KafkaTransactionManager<String, String> kafkaTransactionManager(
ProducerFactory<String, String> producerFactory) {
return new KafkaTransactionManager<>(producerFactory);
}
19. 微服务相关配置
19.1 服务注册与发现
使用Eureka的配置示例:
- 客户端配置:
yaml复制eureka:
client:
serviceUrl:
defaultZone: http://localhost:8761/eureka/
instance:
instance-id: ${spring.application.name}:${random.value}
prefer-ip-address: true
lease-renewal-interval-in-seconds: 30
lease-expiration-duration-in-seconds: 90
- 健康检查增强:
java复制@Bean
public EurekaHealthCheckHandler eurekaHealthCheckHandler(HealthAggregator healthAggregator) {
return new EurekaHealthCheckHandler(healthAggregator);
}
19.2 分布式追踪
Sleuth + Zipkin集成:
- 依赖配置:
xml复制<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-sleuth</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-sleuth-zipkin</artifactId>
</dependency>
- 采样率配置:
yaml复制spring:
sleuth:
sampler:
probability: 0.5
zipkin:
base-url: http://localhost:9411/
sender:
type: web
- 自定义跟踪:
java复制@Autowired
private Tracer tracer;
public void someMethod() {
Span span = tracer.nextSpan().name("custom-operation").start();
try (SpanInScope ws = tracer.withSpan(span.start())) {
// 业务逻辑
} finally {
span.end();
}
}
20. 前端集成策略
20.1 静态资源处理
SpringBoot默认静态资源位置:
- classpath:/static/
- classpath:/public/
- classpath:/resources/
- classpath:/META-INF/resources/
自定义配置示例:
yaml复制spring:
mvc:
static-path-pattern: /assets/**
web:
resources:
static-locations: classpath:/web/
缓存控制策略:
java复制@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/assets/**")
.addResourceLocations("classpath:/web/")
.setCacheControl(CacheControl.maxAge(365, TimeUnit.DAYS));
}
}
20.2 跨域解决方案
生产环境CORS配置:
java复制@Configuration
public class CorsConfig {
@Bean
public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurer() {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/api/**")
.allowedOrigins("https://yourdomain.com")
.allowedMethods("GET", "POST", "PUT", "DELETE")
.allowedHeaders("*")
.allowCredentials(true)
.maxAge(3600);
}
};
}
}
安全增强配置:
yaml复制spring:
mvc:
pathmatch:
matching-strategy: ant_path_matcher
web:
resources:
chain:
strategy:
content:
enabled: true
paths: /**
21. 国际化和本地化
21.1 多语言实现
标准国际化配置:
- 消息文件位置:
code复制src/main/resources/
├── messages.properties
├── messages_zh_CN.properties
└── messages_en_US.properties
- 配置Locale解析器:
java复制@Bean
public LocaleResolver localeResolver() {
SessionLocaleResolver slr = new SessionLocaleResolver();
slr.setDefaultLocale(Locale.US);
return slr;
}
@Bean
public LocaleChangeInterceptor localeChangeInterceptor() {
LocaleChangeInterceptor lci = new LocaleChangeInterceptor();
lci.setParamName("lang");
return lci;
}
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(localeChangeInterceptor());
}
- 使用消息:
java复制@Autowired
private MessageSource messageSource;
public String getMessage(String code, Object[] args, Locale locale) {
return messageSource.getMessage(code, args, locale);
}
21.2 时区处理
统一时区方案:
- 应用启动时设置:
java复制@PostConstruct
public void init() {
TimeZone.setDefault(TimeZone.getTimeZone("Asia/Shanghai"));
}
- 数据库连接时区:
yaml复制spring:
datasource:
url: jdbc:mysql://localhost:3306/db?useSSL=false&serverTimezone=Asia/Shanghai
- Jackson日期序列化:
java复制@Bean
public Jackson2ObjectMapperBuilderCustomizer jacksonCustomizer() {
return builder -> {
builder.timeZone(TimeZone.getTimeZone("Asia/Shanghai"));
builder.simpleDateFormat("yyyy-MM-dd HH:mm:ss");
};
}
22. 测试策略与实践
22.1 单元测试规范
我的测试类结构示例:
java复制@SpringBootTest
@ActiveProfiles("test")
class ProductServiceTest {
@Autowired
private ProductService productService;
@MockBean
private ProductRepository productRepository;
@Test
void getProductById_shouldReturnProduct() {
// Given
Product mockProduct = new Product(1L, "Test");
given(productRepository.findById(1L)).willReturn(Optional.of(mockProduct));
// When
Product result = productService.getProductById(1L);
// Then
assertThat(result).isNotNull();
assertThat(result.getName()).isEqualTo("Test");
}
}
测试覆盖率检查:
bash复制mvn test jacoco:report
22.2 集成测试方案
使用TestContainers的真实测试:
java复制@Testcontainers
@SpringBootTest
class OrderIntegrationTest {
@Container
static PostgreSQLContainer<?> postgres = new PostgreSQLContainer<>("postgres:13")
.withDatabaseName("
