Skip to content
清晨的一缕阳光
返回

Spring Boot 生产最佳实践

前言

生产环境的应用需要关注安全性、性能、可维护性等多个方面。遵循最佳实践可以降低风险、提升稳定性。本文将介绍 Spring Boot 生产最佳实践。

配置管理

1. 敏感信息保护

# ✅ 推荐 - 使用环境变量
spring:
  datasource:
    url: jdbc:mysql://${DB_HOST}:${DB_PORT}/${DB_NAME}
    username: ${DB_USERNAME}
    password: ${DB_PASSWORD}

# ❌ 不推荐 - 硬编码
spring:
  datasource:
    url: jdbc:mysql://localhost:3306/demo
    username: root
    password: 123456

2. 配置中心

<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
# bootstrap.yml
spring:
  cloud:
    nacos:
      config:
        server-addr: nacos:8848
        file-extension: yaml
        namespace: ${NAMESPACE:prod}
        group: DEFAULT_GROUP

3. 配置加密

<dependency>
    <groupId>com.github.ulisesbocchio</groupId>
    <artifactId>jasypt-spring-boot-starter</artifactId>
</dependency>
jasypt:
  encryptor:
    password: ${JASYPT_PASSWORD}

spring:
  datasource:
    password: ENC(加密后的密码)

安全加固

1. 端点安全

management:
  endpoints:
    web:
      exposure:
        include: health,info,prometheus
  endpoint:
    health:
      show-details: never
  server:
    port: 9090
    address: 127.0.0.1
@Configuration
@EnableWebSecurity
public class ActuatorSecurityConfig {
    
    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http
            .securityMatcher(EndpointRequest.toAnyEndpoint())
            .authorizeHttpRequests(authorize -> authorize
                .requestMatchers(EndpointRequest.to("health", "info")).permitAll()
                .anyRequest().hasRole("ADMIN")
            )
            .httpBasic(Customizer.withDefaults());
        
        return http.build();
    }
}

2. 请求防护

@Configuration
public class SecurityConfig {
    
    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http
            .csrf(csrf -> csrf
                .ignoringRequestMatchers("/api/**")
                .csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
            )
            .headers(headers -> headers
                .contentSecurityPolicy(policy -> policy
                    .policyDirectives("default-src 'self'")
                )
                .frameOptions(frame -> frame.deny())
                .xssProtection(xss -> xss.enable(true))
            );
        
        return http.build();
    }
}

3. 依赖安全

# 检查依赖漏洞
mvn org.owasp:dependency-check-maven:check

# 使用安全版本
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter</artifactId>
    <version>4.0.0</version> <!-- 使用最新安全版本 -->
</dependency>

性能优化

1. JVM 调优

# 生产环境 JVM 参数
java -Xms4g -Xmx4g \
     -XX:MetaspaceSize=256m \
     -XX:MaxMetaspaceSize=512m \
     -XX:+UseG1GC \
     -XX:MaxGCPauseMillis=200 \
     -XX:+HeapDumpOnOutOfMemoryError \
     -XX:HeapDumpPath=/var/log/heapdump.hprof \
     -jar app.jar

2. 连接池优化

spring:
  datasource:
    hikari:
      maximum-pool-size: 20
      minimum-idle: 5
      connection-timeout: 30000
      idle-timeout: 600000
      max-lifetime: 1800000
      leak-detection-threshold: 60000

3. 缓存策略

@Configuration
@EnableCaching
public class CacheConfig {
    
    @Bean
    public CacheManager cacheManager() {
        CaffeineCacheManager cacheManager = new CaffeineCacheManager();
        cacheManager.setCaffeine(Caffeine.newBuilder()
            .initialCapacity(100)
            .maximumSize(10000)
            .expireAfterWrite(10, TimeUnit.MINUTES)
            .recordStats()
        );
        return cacheManager;
    }
}
@Service
public class UserService {
    
    @Cacheable(value = "users", key = "#id")
    public UserDTO getUserById(Long id) {
        return userRepository.findById(id)
            .map(this::convertToDTO)
            .orElse(null);
    }
    
    @CachePut(value = "users", key = "#user.id")
    public UserDTO updateUser(UserDTO user) {
        return userRepository.save(convert(user));
    }
    
    @CacheEvict(value = "users", key = "#id")
    public void deleteUser(Long id) {
        userRepository.deleteById(id);
    }
}

4. 异步处理

@Configuration
@EnableAsync
public class AsyncConfig {
    
    @Bean
    public Executor taskExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(10);
        executor.setMaxPoolSize(50);
        executor.setQueueCapacity(100);
        executor.setThreadNamePrefix("async-");
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        return executor;
    }
}
@Service
public class NotificationService {
    
    @Async
    public CompletableFuture<Void> sendEmail(String to, String content) {
        // 异步发送邮件
        emailService.send(to, content);
        return CompletableFuture.completedFuture(null);
    }
}

运维监控

1. 健康检查

management:
  health:
    livenessState:
      enabled: true
    readinessState:
      enabled: true
  endpoint:
    health:
      probes:
        enabled: true
# Kubernetes 探针
livenessProbe:
  httpGet:
    path: /actuator/health/liveness
    port: 8080
  initialDelaySeconds: 30
  periodSeconds: 10

readinessProbe:
  httpGet:
    path: /actuator/health/readiness
    port: 8080
  initialDelaySeconds: 10
  periodSeconds: 5

2. 指标监控

management:
  metrics:
    export:
      prometheus:
        enabled: true
    tags:
      application: ${spring.application.name}
      environment: ${spring.profiles.active}

3. 日志管理

logging:
  level:
    root: INFO
    com.example.demo: INFO
  pattern:
    console: "%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n"
  file:
    name: /var/log/app/app.log
    max-size: 100MB
    max-history: 30
    total-size-cap: 10GB
<!-- Logback 配置 -->
<configuration>
    <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <file>/var/log/app/app.log</file>
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
        </encoder>
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <fileNamePattern>/var/log/app/app.%d{yyyy-MM-dd}.%i.log</fileNamePattern>
            <maxFileSize>100MB</maxFileSize>
            <maxHistory>30</maxHistory>
        </rollingPolicy>
    </appender>
    
    <root level="INFO">
        <appender-ref ref="FILE"/>
    </root>
</configuration>

4. 链路追踪

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-sleuth</artifactId>
</dependency>
spring:
  cloud:
    sleuth:
      sampler:
        probability: 0.1  # 10% 采样

部署实践

1. Docker 优化

# 多阶段构建
FROM maven:3.9-eclipse-temurin-21 AS build
WORKDIR /app
COPY . .
RUN mvn clean package -DskipTests

FROM eclipse-temurin:21-jre-alpine
WORKDIR /app
COPY --from=build /app/target/*.jar app.jar

# 非 root 用户
RUN addgroup -S appgroup && adduser -S appuser -G appgroup
USER appuser

EXPOSE 8080
ENTRYPOINT ["java", "-jar", "app.jar"]

2. Kubernetes 部署

apiVersion: apps/v1
kind: Deployment
metadata:
  name: demo
spec:
  replicas: 3
  selector:
    matchLabels:
      app: demo
  template:
    spec:
      containers:
        - name: demo
          image: demo:1.0.0
          ports:
            - containerPort: 8080
          resources:
            requests:
              memory: "512Mi"
              cpu: "250m"
            limits:
              memory: "1Gi"
              cpu: "500m"
          livenessProbe:
            httpGet:
              path: /actuator/health/liveness
              port: 8080
            initialDelaySeconds: 30
          readinessProbe:
            httpGet:
              path: /actuator/health/readiness
              port: 8080
            initialDelaySeconds: 10

3. 滚动更新

spec:
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxSurge: 1
      maxUnavailable: 0

容灾备份

1. 数据库备份

#!/bin/bash
# backup.sh

BACKUP_DIR="/backup/mysql"
DATE=$(date +%Y%m%d_%H%M%S)

mysqldemo -h localhost -u root -pPASSWORD demo > ${BACKUP_DIR}/demo_${DATE}.sql

# 保留最近 7 天备份
find ${BACKUP_DIR} -name "demo_*.sql" -mtime +7 -delete

2. 多活架构

# 多数据源配置
spring:
  datasource:
    dynamic:
      primary: master
      datasource:
        master:
          url: jdbc:mysql://master:3306/demo
        slave:
          url: jdbc:mysql://slave:3306/demo

3. 限流降级

@Service
public class OrderService {
    
    @SentinelResource(value = "createOrder", 
                      blockHandler = "handleBlock",
                      fallback = "handleFallback")
    public Order createOrder(OrderCreateDTO dto) {
        // 业务逻辑
    }
    
    public Order handleBlock(OrderCreateDTO dto, BlockException ex) {
        log.warn("限流:{}", dto);
        return null;
    }
    
    public Order handleFallback(OrderCreateDTO dto, Throwable ex) {
        log.error("降级:{}", dto, ex);
        return null;
    }
}

最佳实践清单

上线前检查

- [ ] 代码审查通过
- [ ] 单元测试通过
- [ ] 集成测试通过
- [ ] 性能测试通过
- [ ] 安全扫描通过
- [ ] 配置检查完成
- [ ] 监控告警配置
- [ ] 备份策略配置
- [ ] 回滚方案准备
- [ ] 应急预案准备

运维检查

- [ ] CPU 使用率 < 70%
- [ ] 内存使用率 < 80%
- [ ] 磁盘使用率 < 80%
- [ ] 错误率 < 0.1%
- [ ] 响应时间 < 500ms
- [ ] 数据库连接正常
- [ ] 缓存命中率 > 90%
- [ ] 日志正常无异常

总结

生产最佳实践要点:

遵循最佳实践,保障生产稳定。


分享这篇文章到:

上一篇文章
Spring Boot CI/CD 流水线实战
下一篇文章
Feign 高级特性