Spring Boot学习知识点大全(三)

简介: 教程来源 https://app-a6nw7st4g741.appmiaoda.com/ 系统梳理Spring Boot核心实践:涵盖日志分级配置与异步输出、单元/集成测试、Actuator监控与自定义指标、Docker/K8s部署、Spring Boot 3.x Jakarta迁移及虚拟线程等新特性,助力构建高可用生产级应用。

七、日志管理

7.1 日志配置

yaml
# application.yml
logging:
  level:
    root: INFO
    com.example: DEBUG
    org.springframework.web: INFO
    org.hibernate: WARN
    org.mybatis: DEBUG
  file:
    name: logs/application.log
    path: logs/
    max-size: 10MB
    max-history: 30
  pattern:
    console: '%d{yyyy-MM-dd HH:mm:ss} - %msg%n'
    file: '%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n'
    dateformat: yyyy-MM-dd HH:mm:ss.SSS
xml
<!-- logback-spring.xml -->
<configuration>
    <property name="LOG_PATH" value="${LOG_PATH:-${user.home}/logs}"/>
    <property name="LOG_PATTERN" 
              value="%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n"/>

    <!-- 控制台输出 -->
    <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern>${LOG_PATTERN}</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.gz</fileNamePattern>
            <maxHistory>30</maxHistory>
        </rollingPolicy>
        <encoder>
            <pattern>${LOG_PATTERN}</pattern>
        </encoder>
    </appender>

    <!-- 错误日志单独文件 -->
    <appender name="ERROR_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <file>${LOG_PATH}/error.log</file>
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>ERROR</level>
        </filter>
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>${LOG_PATH}/error.%d{yyyy-MM-dd}.log.gz</fileNamePattern>
        </rollingPolicy>
        <encoder>
            <pattern>${LOG_PATTERN}</pattern>
        </encoder>
    </appender>

    <!-- 异步日志 -->
    <appender name="ASYNC_FILE" class="ch.qos.logback.classic.AsyncAppender">
        <queueSize>512</queueSize>
        <discardingThreshold>0</discardingThreshold>
        <appender-ref ref="FILE"/>
    </appender>

    <root level="INFO">
        <appender-ref ref="CONSOLE"/>
        <appender-ref ref="ASYNC_FILE"/>
        <appender-ref ref="ERROR_FILE"/>
    </root>

    <logger name="com.example" level="DEBUG"/>
</configuration>

7.2 日志使用

java
@RestController
@Slf4j
public class UserController {

    @GetMapping("/users/{id}")
    public User getUser(@PathVariable Long id) {
        log.debug("查询用户: id={}", id);

        User user = userService.findById(id);

        if (user == null) {
            log.warn("用户不存在: id={}", id);
        } else {
            log.info("用户信息: {}", user);
        }

        return user;
    }

    @PostMapping("/users")
    public User createUser(@RequestBody User user) {
        log.info("创建用户: {}", user);

        try {
            User result = userService.create(user);
            log.info("创建成功: id={}", result.getId());
            return result;
        } catch (Exception e) {
            log.error("创建用户失败: {}", user, e);
            throw e;
        }
    }
}

八、测试

8.1 单元测试

@SpringBootTest
@AutoConfigureMockMvc
@Transactional
@Rollback
public class UserControllerTest {

    @Autowired
    private MockMvc mockMvc;

    @Autowired
    private ObjectMapper objectMapper;

    @Test
    public void testGetUser() throws Exception {
        mockMvc.perform(get("/api/users/1")
                .contentType(MediaType.APPLICATION_JSON))
                .andExpect(status().isOk())
                .andExpect(jsonPath("$.code").value(200))
                .andExpect(jsonPath("$.data.id").value(1))
                .andDo(print());
    }

    @Test
    public void testCreateUser() throws Exception {
        User user = new User("张三", 25);

        mockMvc.perform(post("/api/users")
                .contentType(MediaType.APPLICATION_JSON)
                .content(objectMapper.writeValueAsString(user)))
                .andExpect(status().isCreated())
                .andExpect(jsonPath("$.data.username").value("张三"));
    }

    @Test
    public void testValidationError() throws Exception {
        User user = new User("", -1);

        mockMvc.perform(post("/api/users")
                .contentType(MediaType.APPLICATION_JSON)
                .content(objectMapper.writeValueAsString(user)))
                .andExpect(status().isBadRequest())
                .andExpect(jsonPath("$.code").value(400));
    }

    @Test
    public void testPageQuery() throws Exception {
        mockMvc.perform(get("/api/users")
                .param("page", "1")
                .param("size", "10")
                .param("keyword", "张三"))
                .andExpect(status().isOk())
                .andExpect(jsonPath("$.data.records").isArray())
                .andExpect(jsonPath("$.data.total").isNumber());
    }
}

8.2 集成测试

@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@Testcontainers
public class IntegrationTest {

    @LocalServerPort
    private int port;

    @Container
    static MySQLContainer<?> mysql = new MySQLContainer<>("mysql:8.0")
            .withDatabaseName("testdb")
            .withUsername("test")
            .withPassword("test");

    @Container
    static GenericContainer<?> redis = new GenericContainer<>("redis:7")
            .withExposedPorts(6379);

    @Test
    public void testDatabaseConnection() {
        assertTrue(mysql.isRunning());
        assertTrue(redis.isRunning());
    }

    @Test
    public void testApiCall() {
        RestTemplate restTemplate = new RestTemplate();
        String url = "http://localhost:" + port + "/api/health";
        String response = restTemplate.getForObject(url, String.class);
        assertNotNull(response);
    }
}

九、生产就绪特性

9.1 Actuator 监控

yaml
# application.yml
management:
  server:
    port: 8081
    address: 127.0.0.1
  endpoints:
    web:
      exposure:
        include: health,info,metrics,env,beans,mappings,threaddump,heapdump
      base-path: /actuator
    jmx:
      exposure:
        include: '*'
  endpoint:
    health:
      show-details: always
      show-components: always
    info:
      git:
        mode: full
    metrics:
      enabled: true
    prometheus:
      enabled: true
  metrics:
    export:
      prometheus:
        enabled: true
    tags:
      application: ${spring.application.name}
java
// 自定义健康检查
@Component
public class CustomHealthIndicator implements HealthIndicator {

    @Autowired
    private DataSource dataSource;

    @Override
    public Health health() {
        try {
            dataSource.getConnection().isValid(5);
            return Health.up()
                .withDetail("database", "connected")
                .withDetail("timestamp", System.currentTimeMillis())
                .build();
        } catch (Exception e) {
            return Health.down()
                .withDetail("error", e.getMessage())
                .build();
        }
    }
}

// 自定义信息端点
@Component
public class CustomInfoContributor implements InfoContributor {

    @Override
    public void contribute(Builder builder) {
        builder.withDetail("app", Map.of(
            "name", "Spring Boot Demo",
            "version", "1.0.0",
            "description", "示例应用"
        ));

        builder.withDetail("build", Map.of(
            "time", Instant.now().toString(),
            "user", System.getProperty("user.name")
        ));
    }
}

// 自定义度量指标
@Component
public class CustomMetrics {

    @Autowired
    private MeterRegistry meterRegistry;

    public void recordUserLogin(String username) {
        meterRegistry.counter("user.login.total", "username", username).increment();
    }

    public void recordApiCall(String api, long duration) {
        meterRegistry.timer("api.call.duration", "api", api)
            .record(duration, TimeUnit.MILLISECONDS);
    }
}

9.2 性能监控

@Aspect
@Component
public class PerformanceAspect {

    private static final Logger log = LoggerFactory.getLogger(PerformanceAspect.class);

    @Around("@annotation(com.example.annotation.Monitor)")
    public Object monitor(ProceedingJoinPoint pjp) throws Throwable {
        String className = pjp.getTarget().getClass().getSimpleName();
        String methodName = pjp.getSignature().getName();

        long start = System.currentTimeMillis();
        try {
            Object result = pjp.proceed();
            long elapsed = System.currentTimeMillis() - start;

            if (elapsed > 1000) {
                log.warn("慢方法: {}.{} - 耗时: {}ms", className, methodName, elapsed);
            } else {
                log.debug("{}.{} - 耗时: {}ms", className, methodName, elapsed);
            }

            return result;
        } catch (Exception e) {
            long elapsed = System.currentTimeMillis() - start;
            log.error("{}.{} 执行异常, 耗时: {}ms", className, methodName, elapsed, e);
            throw e;
        }
    }
}

十、部署与运维

10.1 打包与部署

xml
<!-- Maven 打包配置 -->
<build>
    <finalName>app</finalName>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
            <configuration>
                <executable>true</executable>
                <mainClass>com.example.Application</mainClass>
            </configuration>
        </plugin>
    </plugins>
</build>
bash
# 打包
mvn clean package

# 启动
java -jar target/app.jar

# 指定环境
java -jar target/app.jar --spring.profiles.active=prod

# 指定内存
java -Xms512m -Xmx1024m -jar target/app.jar

# 后台运行
nohup java -jar target/app.jar > app.log 2>&1 &

# 使用 Systemd 管理
# /etc/systemd/system/app.service
[Unit]
Description=Spring Boot App
After=network.target

[Service]
Type=simple
User=appuser
WorkingDirectory=/opt/app
ExecStart=/usr/bin/java -jar /opt/app/app.jar
Restart=on-failure
RestartSec=10

[Install]
WantedBy=multi-user.target

10.2 Docker 部署

dockerfile
# Dockerfile
FROM openjdk:17-jdk-slim AS builder
WORKDIR /app
COPY . .
RUN ./mvnw clean package -DskipTests

FROM openjdk:17-jre-slim
WORKDIR /app
COPY --from=builder /app/target/app.jar app.jar
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "app.jar"]
yaml
# docker-compose.yml
version: '3.8'
services:
  app:
    build: .
    ports:
      - "8080:8080"
    environment:
      - SPRING_PROFILES_ACTIVE=prod
      - SPRING_DATASOURCE_URL=jdbc:mysql://mysql:3306/mydb
    depends_on:
      - mysql
      - redis
    networks:
      - app-network

  mysql:
    image: mysql:8.0
    environment:
      MYSQL_ROOT_PASSWORD: 123456
      MYSQL_DATABASE: mydb
    volumes:
      - mysql-data:/var/lib/mysql
    ports:
      - "3306:3306"
    networks:
      - app-network

  redis:
    image: redis:7-alpine
    ports:
      - "6379:6379"
    networks:
      - app-network

volumes:
  mysql-data:

networks:
  app-network:
    driver: bridge

10.3 Kubernetes 部署

yaml
# deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: spring-boot-app
spec:
  replicas: 3
  selector:
    matchLabels:
      app: spring-boot-app
  template:
    metadata:
      labels:
        app: spring-boot-app
    spec:
      containers:
      - name: app
        image: myregistry/spring-boot-app:latest
        ports:
        - containerPort: 8080
        env:
        - name: SPRING_PROFILES_ACTIVE
          value: "k8s"
        - name: SPRING_DATASOURCE_URL
          value: "jdbc:mysql://mysql-service:3306/mydb"
        resources:
          requests:
            memory: "512Mi"
            cpu: "250m"
          limits:
            memory: "1Gi"
            cpu: "500m"
        livenessProbe:
          httpGet:
            path: /actuator/health/liveness
            port: 8080
          initialDelaySeconds: 60
          periodSeconds: 10
        readinessProbe:
          httpGet:
            path: /actuator/health/readiness
            port: 8080
          initialDelaySeconds: 30
          periodSeconds: 5

---
apiVersion: v1
kind: Service
metadata:
  name: spring-boot-app-service
spec:
  selector:
    app: spring-boot-app
  ports:
  - port: 80
    targetPort: 8080
  type: LoadBalancer

---
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: spring-boot-app-hpa
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: spring-boot-app
  minReplicas: 2
  maxReplicas: 10
  metrics:
  - type: Resource
    resource:
      name: cpu
      target:
        type: Utilization
        averageUtilization: 70
  - type: Resource
    resource:
      name: memory
      target:
        type: Utilization
        averageUtilization: 80

十一、Spring Boot 新特性

11.1 Spring Boot 3.x 新特性

// Jakarta EE 迁移(javax → jakarta)
import jakarta.persistence.Entity;
import jakarta.persistence.Table;

// GraalVM 原生镜像支持
@SpringBootApplication
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

// 构建原生镜像
// mvn -Pnative native:compile

// 问题详细(Problem Details)支持
@RestController
public class ProblemDetailsController {

    @GetMapping("/error")
    public ProblemDetail handleError() {
        ProblemDetail problem = ProblemDetail.forStatus(HttpStatus.NOT_FOUND);
        problem.setTitle("Resource Not Found");
        problem.setDetail("The requested resource was not found");
        problem.setProperty("timestamp", Instant.now());
        return problem;
    }
}

11.2 Spring Boot 3.2 新特性

// 虚拟线程支持
@Configuration
public class VirtualThreadConfig {

    @Bean
    public TomcatProtocolHandlerCustomizer<?> protocolHandlerCustomizer() {
        return protocolHandler -> {
            protocolHandler.setExecutor(Executors.newVirtualThreadPerTaskExecutor());
        };
    }
}

// 或通过配置
spring.threads.virtual.enabled=true

// 新的 RestClient
@Configuration
public class RestClientConfig {

    @Bean
    public RestClient restClient(RestClient.Builder builder) {
        return builder
            .baseUrl("https://api.example.com")
            .defaultHeader("Accept", "application/json")
            .build();
    }
}

Spring Boot 作为 Java 生态中最受欢迎的框架,以其简洁的配置、强大的功能和出色的开发体验,极大地提升了开发效率。本文系统性地梳理了 Spring Boot 的核心知识点,从基础入门到高级特性,从数据访问到生产部署,帮助开发者建立完整的知识体系。
来源:
https://app-a6nw7st4g741.appmiaoda.com/

相关文章
|
23天前
|
XML Java Maven
Spring Boot学习知识点大全(一)
教程来源 https://app-a87ujc988w01.appmiaoda.com/ Spring Boot 是 Spring 家族中革命性框架,秉持“约定优于配置”理念,通过自动配置、起步依赖、嵌入式服务器等特性,大幅简化企业级 Java 应用开发。本文系统梳理其核心概念、注解、多环境配置与最佳实践,助初学者快速入门,为进阶开发者提供深度参考。
|
1月前
|
存储 人工智能 关系型数据库
OpenClaw怎么可能没痛点?用RDS插件来释放OpenClaw全部潜力
OpenClaw插件是深度介入Agent生命周期的扩展机制,提供24个钩子,支持自动注入知识、持久化记忆等被动式干预。相比Skill/Tool,插件可主动在关键节点(如对话开始/结束)执行逻辑,适用于RAG增强、云化记忆等高级场景。
888 56
OpenClaw怎么可能没痛点?用RDS插件来释放OpenClaw全部潜力
|
18天前
|
存储 消息中间件 关系型数据库
(二)走进阿里云实时计算Flink版-场景案例篇
阿里云实时计算Flink版产品负责人黄鹏程(马格)介绍:基于Apache Flink打造的企业级全托管实时计算平台,支持批流一体、湖仓融合、实时风控与AI推理等场景,助力满帮、车企等客户降本增效35%,SLA达99.9%。
393 3
(二)走进阿里云实时计算Flink版-场景案例篇
|
24天前
|
存储 缓存 NoSQL
4-Redis篇-1
本文详解Redis在项目中的三大应用:热点缓存、业务数据存储(如验证码、排行榜)及分布式锁;涵盖5种基础数据类型、RDB/AOF双持久化机制、惰性+定期混合过期策略,以及8种内存淘汰策略。
|
1月前
|
弹性计算 运维 监控
阿里云2核2G配置38元和99元特价云服务器测评:实例性能、适用场景解析
2026年阿里云推出特价云服务器,其中38元/年轻量应用服务器和99元/年云服务器ECS经济型e实例受大量个人开发者、初创企业及学生关注。38元轻量服务器部署简易、运维简化、带宽弹性大,适合个人博客、小微应用测试等场景;99元ECS经济型e实例性能基础、长期成本稳定,适合小型企业官网、开发测试等场景。此外,还有199元/年的通用算力型u1实例可供选择。用户应理性评估自身业务需求,做出明智选择。
|
10天前
|
运维 Kubernetes 应用服务中间件
CI/CD流水线镜像拉取耗时从47分钟降到2分钟,我做了这几件事
换镜像加速源,CI/CD构建从47分钟骤降至2分钟!非代码/硬件优化,仅切换为毫秒镜像(1ms.run)——全源加速(Docker Hub、GHCR、k8s.gcr等),30台服务器10分钟批量配置,失败率归零,凌晨发布成功率100%。
100 16
|
10天前
|
人工智能 供应链 安全
2026 年网络威胁态势与智能防御体系研究 —— 基于 Check Point 威胁情报报告
本文基于Check Point 2026年4月威胁情报,系统剖析AI驱动攻击、供应链入侵、高危零日漏洞及定向威胁新趋势;提出以威胁情报驱动、AI检测、漏洞闭环、零信任与供应链安全为核心的一体化防御体系,并提供可落地的检测代码、配置与响应流程。(239字)
228 13
|
20天前
|
存储 并行计算 数据可视化
大模型应用:GPU的黑盒拆解:可视化看透大模型并行计算的底层逻辑.67
本文深入解析GPU核心架构与大模型算力优化原理,涵盖SM流式多处理器、显存、显存控制器、PCIe接口等关键组件,详解线程级/指令级并行及张量核心加速机制,并通过全流程耗时分析与任务拆分可视化,揭示“数据传输是主要瓶颈”的核心结论,助力高效部署大模型。
242 6
|
24天前
|
缓存 NoSQL 调度
4-Redis篇-4
本文详解Redis三大核心问题:缓存雪崩(大量key同时失效,需加随机过期时间)、热点数据保障(采用LFU淘汰策略)、分布式锁实现(基于SETNX,解决死锁、超时、归一、可重入及阻塞等问题),并附实战应用案例。

热门文章

最新文章

下一篇
开通oss服务