
云原生架构的普及,对Java应用的启动速度、内存占用、弹性伸缩能力提出了全新要求。Spring Boot 3 作为Spring生态里程碑式的版本,基于Spring Framework 6构建,完成了从底层架构到上层能力的全面云原生重构,配合Spring Cloud 2024.x版本的微服务能力升级,彻底解决了传统Java应用在容器化、Serverless场景下的核心痛点。
Spring Boot 3的所有新特性,都建立在三大底层架构变更之上,这也是它与Spring Boot 2.x最核心的区别。
Spring Boot 3将最低JDK版本要求提升至JDK 17,这是一次跨越性的升级。JDK 17作为Oracle官方的长期支持(LTS)版本,提供了多项提升开发效率与运行性能的核心特性,Spring Boot 3对其进行了原生适配:
Oracle将Java EE捐赠给Eclipse基金会后,Java EE正式更名为Jakarta EE,所有核心包名从javax.*全面变更为jakarta.*。Spring Boot 3完成了全生态的迁移,彻底告别了javax包:
javax.servlet变更为jakarta.servletjavax.persistence变更为jakarta.persistencejavax.validation变更为jakarta.validation这是Spring Boot 3最核心的不兼容变更,也是旧版本升级的核心卡点,所有第三方组件都需要完成Jakarta EE适配才能正常使用。
Spring Boot 3完全基于Spring Framework 6构建,后者带来了云原生场景下的核心能力升级:

Spring Boot 3 AOT编译与原生镜像生成流程
传统Java应用基于JVM的JIT即时编译,启动时需要加载字节码、解析Bean定义、动态生成代理类,导致启动慢、内存占用高,在Serverless、函数计算等短生命周期场景下劣势明显。Spring Boot 3内置的AOT提前编译与GraalVM原生镜像支持,彻底解决了这个问题。
AOT提前编译在应用构建阶段执行,完成三项核心工作:
配合GraalVM,将优化后的字节码直接编译为对应平台的机器码,生成独立的可执行文件,实现毫秒级启动、MB级的内存占用。
Maven项目中,只需在pom.xml中添加原生镜像编译插件:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.4.3</version>
<relativePath/>
</parent>
<groupId>com.jam.demo</groupId>
<artifactId>native-demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>native-demo</name>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.34</version>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.graalvm.buildtools</groupId>
<artifactId>native-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
执行mvn native:compile命令,即可在target目录下生成对应平台的可执行文件。
@RegisterReflectionForBinding注解注册反射元数据META-INF/native-image/resource-config.json中声明,或通过@ImportRuntimeHints注册虚拟线程是JDK 19引入的预览特性,在JDK 21正式发布,Spring Boot 3.2+版本提供了全自动的配置支持,无需修改业务代码,即可享受虚拟线程带来的性能提升。
传统的平台线程与操作系统内核线程一一对应,创建成本高、数量受限,当线程执行IO阻塞操作时,内核线程会被挂起,造成资源浪费。
虚拟线程是JVM层面实现的轻量级线程,调度由JVM全权管理,多个虚拟线程会映射到少量的平台线程上执行。当虚拟线程执行IO阻塞操作时,JVM会自动释放对应的平台线程,分配给其他虚拟线程使用,实现了阻塞操作不阻塞内核线程的效果。开发者可以轻松创建百万级的虚拟线程,无需担心系统资源耗尽。
只需在application.yml中添加一行配置,即可开启全局虚拟线程支持:
spring:
threads:
virtual:
enabled: true
开启后,Spring Boot会自动完成以下适配:
@Async注解的异步执行线程池替换为虚拟线程TaskScheduler定时任务线程池适配虚拟线程ThreadLocal可以正常使用,但要注意虚拟线程数量巨大,避免存放大量数据导致内存溢出Spring Framework 6引入了全新的声明式HTTP客户端HTTP Interface,采用与MyBatis Mapper类似的设计,只需定义接口,通过注解声明HTTP请求信息,无需编写实现类,即可完成远程HTTP调用,与Spring生态深度集成,比OpenFeign更轻量、更原生。
HTTP Interface基于Java动态代理实现,结合Spring的WebClient非阻塞客户端,将接口方法的调用转换为对应的HTTP请求。Spring会在启动时扫描接口注解,生成动态代理实现类,自动完成参数解析、请求发送、响应解析、异常处理等全流程操作,原生支持负载均衡、响应式编程、拦截器扩展等能力。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
package com.jam.demo.client;
import com.jam.demo.entity.User;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.service.http.GetExchange;
import org.springframework.service.http.HttpExchange;
import org.springframework.service.http.PostExchange;
import java.math.BigDecimal;
/**
* 用户服务HTTP接口客户端
* @author ken
* @date 2026-03-24
*/
@HttpExchange(url = "http://user-service/user")
publicinterface UserClient {
/**
* 根据用户ID查询用户信息
* @param userId 用户ID
* @return 用户信息
*/
@GetExchange("/{userId}")
User getUserById(@PathVariable Long userId);
/**
* 扣减用户余额
* @param userId 用户ID
* @param amount 扣减金额
* @return 扣减结果
*/
@PostExchange("/deduct")
boolean deductBalance(@RequestParam Long userId, @RequestParam BigDecimal amount);
}
package com.jam.demo.config;
import com.jam.demo.client.UserClient;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.reactive.function.client.WebClient;
import org.springframework.web.reactive.function.client.support.WebClientAdapter;
import org.springframework.service.http.HttpServiceProxyFactory;
/**
* HTTP客户端配置类
* @author ken
* @date 2026-03-24
*/
@Configuration
publicclass HttpInterfaceConfig {
@Bean
@LoadBalanced
public WebClient.Builder webClientBuilder() {
return WebClient.builder();
}
@Bean
public UserClient userClient(WebClient.Builder webClientBuilder) {
WebClient webClient = webClientBuilder.baseUrl("http://user-service").build();
HttpServiceProxyFactory factory = HttpServiceProxyFactory.builderFor(WebClientAdapter.create(webClient)).build();
return factory.createClient(UserClient.class);
}
}
@Service
publicclass OrderService {
privatefinal UserClient userClient;
public OrderService(UserClient userClient) {
this.userClient = userClient;
}
public void createOrder(Long userId, BigDecimal amount) {
User user = userClient.getUserById(userId);
boolean deductResult = userClient.deductBalance(userId, amount);
// 后续订单创建逻辑
}
}
特性 | HTTP Interface | OpenFeign |
|---|---|---|
所属生态 | Spring Framework 6原生 | Spring Cloud Netflix组件 |
底层实现 | 基于WebClient,原生支持响应式 | 基于HttpURLConnection/OkHttp,同步为主 |
依赖要求 | 仅需webflux依赖,无额外依赖 | 需要引入spring-cloud-starter-openfeign依赖 |
负载均衡 | 配合LoadBalanced注解原生支持 | 原生集成Spring Cloud LoadBalancer |
扩展能力 | 支持拦截器、自定义编解码 | 支持丰富的扩展组件,如重试、熔断、日志等 |
适用场景 | 简单HTTP调用、响应式场景 | 复杂微服务调用、需要丰富扩展能力的场景 |
Spring Boot 3对可观测性体系进行了全面重构,将Micrometer Tracing作为默认的链路追踪实现,彻底替代了停止维护的Spring Cloud Sleuth,统一了指标、日志、链路追踪三大可观测性支柱的编程模型,与云原生可观测性平台无缝集成。
Micrometer是可观测性领域的门面框架,类似SLF4J对于日志的作用。它提供了统一的API,开发者无需关心底层的可观测性后端实现,只需编写一次代码,即可适配Prometheus、Zipkin、Jaeger、Grafana等多种后端系统。
Spring Boot 3自动完成了全链路的埋点适配,HTTP请求、数据库访问、远程调用、消息发送等操作都会自动生成对应的指标与链路数据,traceId会自动在跨服务调用中传递,并自动注入到日志MDC中,实现全链路的问题定位。
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-registry-prometheus</artifactId>
</dependency>
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-tracing-bridge-brave</artifactId>
</dependency>
<dependency>
<groupId>io.zipkin.reporter2</groupId>
<artifactId>zipkin-reporter-brave</artifactId>
</dependency>
</dependencies>
management:
endpoints:
web:
exposure:
include:health,info,prometheus
endpoint:
health:
show-details:always
probes:
enabled:true
metrics:
tags:
application:${spring.application.name}
tracing:
sampling:
probability:1.0
zipkin:
tracing:
endpoint:http://localhost:9411/api/v2/spans
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level [%X{traceId}/%X{spanId}] %logger{50} - %msg%n</pattern>
package com.jam.demo.service.impl;
import com.jam.demo.entity.User;
import com.jam.demo.mapper.UserMapper;
import com.jam.demo.service.UserService;
import io.micrometer.core.instrument.Counter;
import io.micrometer.core.instrument.MeterRegistry;
import io.micrometer.tracing.Span;
import io.micrometer.tracing.Tracer;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;
/**
* 用户服务实现类
* @author ken
* @date 2026-03-24
*/
@Slf4j
@Service
publicclass UserServiceImpl implements UserService {
privatefinal UserMapper userMapper;
privatefinal Tracer tracer;
privatefinal Counter userQueryCounter;
public UserServiceImpl(UserMapper userMapper, Tracer tracer, MeterRegistry meterRegistry) {
this.userMapper = userMapper;
this.tracer = tracer;
this.userQueryCounter = Counter.builder("user.query.count")
.description("用户查询次数统计")
.register(meterRegistry);
}
@Override
public User getUserById(Long userId) {
// 指标统计
userQueryCounter.increment();
// 自定义链路span
Span span = tracer.nextSpan().name("queryUserById").start();
try (Tracer.SpanInScope ws = tracer.withSpan(span)) {
if (ObjectUtils.isEmpty(userId)) {
log.warn("查询用户参数异常,userId:{}", userId);
returnnull;
}
span.tag("userId", String.valueOf(userId));
return userMapper.selectById(userId);
} catch (Exception e) {
span.error(e);
log.error("查询用户异常,userId:{}", userId, e);
returnnull;
} finally {
span.end();
}
}
}
Spring Cloud 2024.0.x(代号Leyton)是适配Spring Boot 3.4.x的最新稳定版本,完成了全组件的Jakarta EE迁移,针对云原生微服务场景进行了多项能力升级,重构了核心组件的架构,适配Kubernetes生态,提升了微服务的弹性、可观测性与开发效率。

Spring Cloud 微服务架构图
Spring Cloud 2024.x完成了多项核心架构调整,淘汰了停止维护的组件,统一了云原生标准:
Spring Cloud Gateway是Spring Cloud官方推荐的API网关,基于Spring WebFlux响应式框架构建,非阻塞、高性能,完美适配云原生场景。3.x版本配合Spring Boot 3完成了多项核心能力升级。
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.4.3</version>
<relativePath/>
</parent>
<groupId>com.jam.demo</groupId>
<artifactId>gateway-service</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>gateway-service</name>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>2024.0.0</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>2023.0.3.0</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-starter-webflux-ui</artifactId>
<version>2.6.0</version>
</dependency>
<dependency>
<groupId>io.github.resilience4j</groupId>
<artifactId>resilience4j-spring-boot3</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-tracing-bridge-brave</artifactId>
</dependency>
<dependency>
<groupId>io.zipkin.reporter2</groupId>
<artifactId>zipkin-reporter-brave</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.34</version>
<scope>provided</scope>
</dependency>
</dependencies>
</project>
server:
port:8080
spring:
application:
name:gateway-service
cloud:
nacos:
discovery:
server-addr:127.0.0.1:8848
gateway:
discovery:
locator:
enabled:true
lower-case-service-id:true
routes:
-id:user-service
uri:lb://user-service
predicates:
-Path=/user/**
filters:
-name:CircuitBreaker
args:
name:userService
fallbackUri:forward:/fallback/user
-id:order-service
uri:lb://order-service
predicates:
-Path=/order/**
filters:
-name:CircuitBreaker
args:
name:orderService
fallbackUri:forward:/fallback/order
springdoc:
swagger-ui:
enabled:true
urls:
-name:用户服务
url:/user/v3/api-docs
-name:订单服务
url:/order/v3/api-docs
resilience4j:
circuitbreaker:
instances:
userService:
slidingWindowSize:10
failureRateThreshold:50
waitDurationInOpenState:10000
permittedNumberOfCallsInHalfOpenState:3
orderService:
slidingWindowSize:10
failureRateThreshold:50
waitDurationInOpenState:10000
permittedNumberOfCallsInHalfOpenState:3
management:
tracing:
sampling:
probability:1.0
zipkin:
tracing:
endpoint:http://localhost:9411/api/v2/spans
package com.jam.demo.gateway.filter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
/**
* 全局请求日志过滤器
* @author ken
* @date 2026-03-24
*/
@Slf4j
@Component
publicclass GlobalLogFilter implements GlobalFilter, Ordered {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
ServerHttpRequest request = exchange.getRequest();
String path = request.getPath().value();
String method = request.getMethod().name();
log.info("网关收到请求,方法:{}, 路径:{}", method, path);
long startTime = System.currentTimeMillis();
return chain.filter(exchange).doFinally(signalType -> {
ServerHttpResponse response = exchange.getResponse();
long duration = System.currentTimeMillis() - startTime;
log.info("网关请求处理完成,方法:{}, 路径:{}, 响应状态:{}, 耗时:{}ms",
method, path, response.getStatusCode(), duration);
});
}
@Override
public int getOrder() {
return Ordered.HIGHEST_PRECEDENCE;
}
}
Spring Cloud OpenFeign 4.x版本完成了Jakarta EE适配,支持Spring Boot 3,同时与Spring 6的HTTP Interface完成了深度融合,提供了更灵活的开发体验。
@HttpExchange、@GetExchange等注解定义Feign客户端,与原生HTTP Interface完全兼容<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
@EnableFeignClients注解package com.jam.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.openfeign.EnableFeignClients;
@SpringBootApplication
@EnableFeignClients
public class OrderServiceApplication {
public static void main(String[] args) {
SpringApplication.run(OrderServiceApplication.class, args);
}
}
package com.jam.demo.client;
import com.jam.demo.entity.User;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import java.math.BigDecimal;
/**
* 用户服务Feign客户端
* @author ken
* @date 2026-03-24
*/
@FeignClient(name = "user-service", path = "/user", fallback = UserClientFallback.class)
public interface UserFeignClient {
@GetMapping("/{userId}")
User getUserById(@PathVariable("userId") Long userId);
@PostMapping("/deduct")
boolean deductBalance(@RequestParam("userId") Long userId, @RequestParam("amount") BigDecimal amount);
}
package com.jam.demo.client;
import com.jam.demo.entity.User;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import java.math.BigDecimal;
/**
* 用户服务降级实现
* @author ken
* @date 2026-03-24
*/
@Slf4j
@Component
publicclass UserClientFallback implements UserFeignClient {
@Override
public User getUserById(Long userId) {
log.warn("查询用户信息触发降级,userId:{}", userId);
returnnull;
}
@Override
public boolean deductBalance(Long userId, BigDecimal amount) {
log.warn("扣减用户余额触发降级,userId:{}, amount:{}", userId, amount);
returnfalse;
}
}
基于Spring Boot 3 + Spring Cloud 2024.x,我们构建一个包含用户服务、订单服务、API网关的完整微服务项目,覆盖服务注册发现、配置管理、远程调用、事务管理、链路追踪、流量治理等核心场景。
CREATE DATABASEIFNOTEXISTS cloud_demo DEFAULTCHARACTERSET utf8mb4 COLLATE utf8mb4_unicode_ci;
USE cloud_demo;
DROPTABLEIFEXISTS t_user;
CREATETABLE t_user (
idBIGINTNOTNULL AUTO_INCREMENT COMMENT'用户ID',
username VARCHAR(64) NOTNULLCOMMENT'用户名',
balance DECIMAL(10,2) NOTNULLDEFAULT0.00COMMENT'用户余额',
create_time DATETIME NOTNULLDEFAULTCURRENT_TIMESTAMPCOMMENT'创建时间',
update_time DATETIME NOTNULLDEFAULTCURRENT_TIMESTAMPONUPDATECURRENT_TIMESTAMPCOMMENT'更新时间',
PRIMARY KEY (id),
UNIQUEKEY uk_username (username)
) ENGINE=InnoDBDEFAULTCHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='用户表';
DROPTABLEIFEXISTS t_order;
CREATETABLE t_order (
idBIGINTNOTNULL AUTO_INCREMENT COMMENT'订单ID',
order_no VARCHAR(64) NOTNULLCOMMENT'订单编号',
user_id BIGINTNOTNULLCOMMENT'用户ID',
amount DECIMAL(10,2) NOTNULLCOMMENT'订单金额',
statusTINYINTNOTNULLDEFAULT0COMMENT'订单状态:0-待支付,1-已支付,2-已取消',
create_time DATETIME NOTNULLDEFAULTCURRENT_TIMESTAMPCOMMENT'创建时间',
update_time DATETIME NOTNULLDEFAULTCURRENT_TIMESTAMPONUPDATECURRENT_TIMESTAMPCOMMENT'更新时间',
PRIMARY KEY (id),
UNIQUEKEY uk_order_no (order_no),
KEY idx_user_id (user_id)
) ENGINE=InnoDBDEFAULTCHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='订单表';
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.4.3</version>
<relativePath/>
</parent>
<groupId>com.jam.demo</groupId>
<artifactId>user-service</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>user-service</name>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>2024.0.0</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>2023.0.3.0</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.7</version>
</dependency>
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
<version>2.6.0</version>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>33.2.0-jre</version>
</dependency>
<dependency>
<groupId>com.alibaba.fastjson2</groupId>
<artifactId>fastjson2</artifactId>
<version>2.0.53</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-tracing-bridge-brave</artifactId>
</dependency>
<dependency>
<groupId>io.zipkin.reporter2</groupId>
<artifactId>zipkin-reporter-brave</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.34</version>
<scope>provided</scope>
</dependency>
</dependencies>
</project>
server:
port:8081
spring:
application:
name:user-service
threads:
virtual:
enabled:true
datasource:
driver-class-name:com.mysql.cj.jdbc.Driver
url:jdbc:mysql://127.0.0.1:3306/cloud_demo?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true
username:root
password:root
cloud:
nacos:
discovery:
server-addr:127.0.0.1:8848
config:
server-addr:127.0.0.1:8848
file-extension:yml
mybatis-plus:
mapper-locations:classpath*:/mapper/**/*.xml
configuration:
map-underscore-to-camel-case:true
log-impl:org.apache.ibatis.logging.stdout.StdOutImpl
global-config:
db-config:
id-type:auto
logic-delete-field:deleted
logic-delete-value:1
logic-not-delete-value:0
springdoc:
api-docs:
enabled:true
swagger-ui:
enabled:true
management:
endpoints:
web:
exposure:
include:health,info
endpoint:
health:
probes:
enabled:true
tracing:
sampling:
probability:1.0
zipkin:
tracing:
endpoint:http://localhost:9411/api/v2/spans
package com.jam.demo.user.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.math.BigDecimal;
import java.time.LocalDateTime;
/**
* 用户实体类
* @author ken
* @date 2026-03-24
*/
@Data
@TableName("t_user")
@Schema(description = "用户信息实体")
publicclass User {
@TableId(type = IdType.AUTO)
@Schema(description = "用户ID", example = "1")
private Long id;
@Schema(description = "用户名", example = "zhangsan")
private String username;
@Schema(description = "用户余额", example = "1000.00")
private BigDecimal balance;
@Schema(description = "创建时间")
private LocalDateTime createTime;
@Schema(description = "更新时间")
private LocalDateTime updateTime;
}
package com.jam.demo.user.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.jam.demo.user.entity.User;
import org.apache.ibatis.annotations.Mapper;
/**
* 用户Mapper接口
* @author ken
* @date 2026-03-24
*/
@Mapper
public interface UserMapper extends BaseMapper<User> {
}
package com.jam.demo.user.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.jam.demo.user.entity.User;
import java.math.BigDecimal;
/**
* 用户服务接口
* @author ken
* @date 2026-03-24
*/
publicinterface UserService extends IService<User> {
/**
* 扣减用户余额
* @param userId 用户ID
* @param amount 扣减金额
* @return 扣减是否成功
*/
boolean deductBalance(Long userId, BigDecimal amount);
/**
* 根据用户ID查询用户信息
* @param userId 用户ID
* @return 用户信息
*/
User getUserById(Long userId);
}
package com.jam.demo.user.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.jam.demo.user.entity.User;
import com.jam.demo.user.mapper.UserMapper;
import com.jam.demo.user.service.UserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.TransactionCallback;
import org.springframework.transaction.support.TransactionTemplate;
import org.springframework.util.ObjectUtils;
import java.math.BigDecimal;
/**
* 用户服务实现类
* @author ken
* @date 2026-03-24
*/
@Slf4j
@Service
publicclass UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
privatefinal TransactionTemplate transactionTemplate;
public UserServiceImpl(TransactionTemplate transactionTemplate) {
this.transactionTemplate = transactionTemplate;
}
@Override
public boolean deductBalance(Long userId, BigDecimal amount) {
if (ObjectUtils.isEmpty(userId) || ObjectUtils.isEmpty(amount) || amount.compareTo(BigDecimal.ZERO) <= 0) {
log.warn("扣减余额参数异常,userId:{}, amount:{}", userId, amount);
returnfalse;
}
return transactionTemplate.execute(new TransactionCallback<Boolean>() {
@Override
public Boolean doInTransaction(TransactionStatus status) {
try {
User user = getById(userId);
if (ObjectUtils.isEmpty(user)) {
log.warn("用户不存在,userId:{}", userId);
returnfalse;
}
if (user.getBalance().compareTo(amount) < 0) {
log.warn("用户余额不足,userId:{}, balance:{}, amount:{}", userId, user.getBalance(), amount);
returnfalse;
}
user.setBalance(user.getBalance().subtract(amount));
boolean updateResult = updateById(user);
if (updateResult) {
log.info("用户余额扣减成功,userId:{}, 扣减金额:{}", userId, amount);
}
return updateResult;
} catch (Exception e) {
status.setRollbackOnly();
log.error("用户余额扣减异常,userId:{}", userId, e);
returnfalse;
}
}
});
}
@Override
public User getUserById(Long userId) {
if (ObjectUtils.isEmpty(userId)) {
log.warn("查询用户参数异常,userId:{}", userId);
returnnull;
}
return getById(userId);
}
}
package com.jam.demo.user.controller;
import com.jam.demo.user.entity.User;
import com.jam.demo.user.service.UserService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;
import java.math.BigDecimal;
/**
* 用户控制器
* @author ken
* @date 2026-03-24
*/
@Slf4j
@RestController
@RequestMapping("/user")
@Tag(name = "用户管理", description = "用户信息查询、余额操作相关接口")
publicclass UserController {
privatefinal UserService userService;
public UserController(UserService userService) {
this.userService = userService;
}
@GetMapping("/{userId}")
@Operation(summary = "根据ID查询用户信息", description = "通过用户ID获取用户的详细信息")
public User getUserById(
@Parameter(description = "用户ID", required = true, example = "1")
@PathVariable Long userId) {
return userService.getUserById(userId);
}
@PostMapping("/deduct")
@Operation(summary = "扣减用户余额", description = "根据用户ID和金额扣减用户账户余额")
public boolean deductBalance(
@Parameter(description = "用户ID", required = true, example = "1")
@RequestParam Long userId,
@Parameter(description = "扣减金额", required = true, example = "100.00")
@RequestParam BigDecimal amount) {
return userService.deductBalance(userId, amount);
}
}
在用户服务的依赖基础上,新增Resilience4j与WebFlux依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
<dependency>
<groupId>io.github.resilience4j</groupId>
<artifactId>resilience4j-spring-boot3</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
server:
port:8082
spring:
application:
name:order-service
threads:
virtual:
enabled:true
datasource:
driver-class-name:com.mysql.cj.jdbc.Driver
url:jdbc:mysql://127.0.0.1:3306/cloud_demo?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true
username:root
password:root
cloud:
nacos:
discovery:
server-addr:127.0.0.1:8848
config:
server-addr:127.0.0.1:8848
file-extension:yml
mybatis-plus:
mapper-locations:classpath*:/mapper/**/*.xml
configuration:
map-underscore-to-camel-case:true
global-config:
db-config:
id-type:auto
springdoc:
api-docs:
enabled:true
swagger-ui:
enabled:true
resilience4j:
circuitbreaker:
instances:
userService:
slidingWindowSize:10
failureRateThreshold:50
waitDurationInOpenState:10000
permittedNumberOfCallsInHalfOpenState:3
retry:
instances:
userService:
maxRetryAttempts:3
waitDuration:1000
enableExponentialBackoff:true
exponentialBackoffMultiplier:2
management:
tracing:
sampling:
probability:1.0
zipkin:
tracing:
endpoint:http://localhost:9411/api/v2/spans
package com.jam.demo.order.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.math.BigDecimal;
import java.time.LocalDateTime;
/**
* 订单实体类
* @author ken
* @date 2026-03-24
*/
@Data
@TableName("t_order")
@Schema(description = "订单信息实体")
publicclass Order {
@TableId(type = IdType.AUTO)
@Schema(description = "订单ID", example = "1")
private Long id;
@Schema(description = "订单编号", example = "202603240001")
private String orderNo;
@Schema(description = "用户ID", example = "1")
private Long userId;
@Schema(description = "订单金额", example = "100.00")
private BigDecimal amount;
@Schema(description = "订单状态:0-待支付,1-已支付,2-已取消", example = "1")
private Integer status;
@Schema(description = "创建时间")
private LocalDateTime createTime;
@Schema(description = "更新时间")
private LocalDateTime updateTime;
}
package com.jam.demo.order.client;
import com.jam.demo.order.entity.User;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.service.http.GetExchange;
import org.springframework.service.http.HttpExchange;
import org.springframework.service.http.PostExchange;
import java.math.BigDecimal;
/**
* 用户服务HTTP接口客户端
* @author ken
* @date 2026-03-24
*/
@HttpExchange(url = "http://user-service/user")
publicinterface UserClient {
@GetExchange("/{userId}")
User getUserById(@PathVariable Long userId);
@PostExchange("/deduct")
boolean deductBalance(@RequestParam Long userId, @RequestParam BigDecimal amount);
}
package com.jam.demo.order.config;
import com.jam.demo.order.client.UserClient;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.reactive.function.client.WebClient;
import org.springframework.web.reactive.function.client.support.WebClientAdapter;
import org.springframework.service.http.HttpServiceProxyFactory;
/**
* HTTP客户端配置类
* @author ken
* @date 2026-03-24
*/
@Configuration
publicclass HttpInterfaceConfig {
@Bean
@LoadBalanced
public WebClient.Builder webClientBuilder() {
return WebClient.builder();
}
@Bean
public UserClient userClient(WebClient.Builder webClientBuilder) {
WebClient webClient = webClientBuilder.baseUrl("http://user-service").build();
HttpServiceProxyFactory factory = HttpServiceProxyFactory.builderFor(WebClientAdapter.create(webClient)).build();
return factory.createClient(UserClient.class);
}
}
package com.jam.demo.order.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.jam.demo.order.entity.Order;
import java.math.BigDecimal;
/**
* 订单服务接口
* @author ken
* @date 2026-03-24
*/
public interface OrderService extends IService<Order> {
/**
* 创建订单
* @param userId 用户ID
* @param amount 订单金额
* @return 订单信息
*/
Order createOrder(Long userId, BigDecimal amount);
}
package com.jam.demo.order.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.jam.demo.order.client.UserClient;
import com.jam.demo.order.entity.Order;
import com.jam.demo.order.mapper.OrderMapper;
import com.jam.demo.order.service.OrderService;
import io.github.resilience4j.circuitbreaker.annotation.CircuitBreaker;
import io.github.resilience4j.retry.annotation.Retry;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.TransactionCallback;
import org.springframework.transaction.support.TransactionTemplate;
import org.springframework.util.ObjectUtils;
import java.math.BigDecimal;
import java.util.UUID;
/**
* 订单服务实现类
* @author ken
* @date 2026-03-24
*/
@Slf4j
@Service
publicclass OrderServiceImpl extends ServiceImpl<OrderMapper, Order> implements OrderService {
privatefinal TransactionTemplate transactionTemplate;
privatefinal UserClient userClient;
public OrderServiceImpl(TransactionTemplate transactionTemplate, UserClient userClient) {
this.transactionTemplate = transactionTemplate;
this.userClient = userClient;
}
@Override
@CircuitBreaker(name = "userService", fallbackMethod = "createOrderFallback")
@Retry(name = "userService", fallbackMethod = "createOrderFallback")
public Order createOrder(Long userId, BigDecimal amount) {
if (ObjectUtils.isEmpty(userId) || ObjectUtils.isEmpty(amount) || amount.compareTo(BigDecimal.ZERO) <= 0) {
log.warn("创建订单参数异常,userId:{}, amount:{}", userId, amount);
returnnull;
}
return transactionTemplate.execute(new TransactionCallback<Order>() {
@Override
public Order doInTransaction(TransactionStatus status) {
try {
boolean deductResult = userClient.deductBalance(userId, amount);
if (!deductResult) {
log.warn("用户余额扣减失败,userId:{}, amount:{}", userId, amount);
status.setRollbackOnly();
returnnull;
}
Order order = new Order();
order.setOrderNo(UUID.randomUUID().toString().replace("-", ""));
order.setUserId(userId);
order.setAmount(amount);
order.setStatus(1);
boolean saveResult = save(order);
if (!saveResult) {
log.warn("订单创建失败,userId:{}, amount:{}", userId, amount);
status.setRollbackOnly();
returnnull;
}
log.info("订单创建成功,orderNo:{}, userId:{}, amount:{}", order.getOrderNo(), userId, amount);
return order;
} catch (Exception e) {
status.setRollbackOnly();
log.error("订单创建异常,userId:{}", userId, e);
throw e;
}
}
});
}
public Order createOrderFallback(Long userId, BigDecimal amount, Exception e) {
log.error("订单创建触发降级,userId:{}, amount:{}", userId, amount, e);
returnnull;
}
}
package com.jam.demo.order.controller;
import com.jam.demo.order.entity.Order;
import com.jam.demo.order.service.OrderService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;
import java.math.BigDecimal;
/**
* 订单控制器
* @author ken
* @date 2026-03-24
*/
@Slf4j
@RestController
@RequestMapping("/order")
@Tag(name = "订单管理", description = "订单创建、查询相关接口")
publicclass OrderController {
privatefinal OrderService orderService;
public OrderController(OrderService orderService) {
this.orderService = orderService;
}
@PostMapping("/create")
@Operation(summary = "创建订单", description = "根据用户ID和订单金额创建订单")
public Order createOrder(
@Parameter(description = "用户ID", required = true, example = "1")
@RequestParam Long userId,
@Parameter(description = "订单金额", required = true, example = "100.00")
@RequestParam BigDecimal amount) {
return orderService.createOrder(userId, amount);
}
@GetMapping("/{orderId}")
@Operation(summary = "根据ID查询订单信息", description = "通过订单ID获取订单的详细信息")
public Order getOrderById(
@Parameter(description = "订单ID", required = true, example = "1")
@PathVariable Long orderId) {
return orderService.getById(orderId);
}
}
这是升级最核心的卡点,所有使用javax.*包的代码都需要替换为jakarta.*,包括:
javax.servlet.* → jakarta.servlet.*javax.validation.* → jakarta.validation.*javax.persistence.* → jakarta.persistence.*javax.annotation.* → jakarta.annotation.*javax.transaction.* → jakarta.transaction.*解决方案:使用IDEA的全局替换功能,配合maven依赖的版本升级,确保所有第三方组件都适配了Jakarta EE 9+,例如MyBatis Plus 3.5.3+、Druid 1.2.16+、Redis客户端Jedis 4.0+。
Spring Boot 3最低要求JDK 17,需要处理JDK版本升级带来的语法变化:
sun.misc.Unsafe的部分方法、finalize()方法module-info.java中声明依赖的模块解决方案:优先使用JDK 17的LTS版本,升级所有第三方组件到支持JDK 17的版本,避免使用过时的API,对于反射受限的场景,添加JVM参数--add-opens java.base/java.lang=ALL-UNNAMED开放对应模块。
Spring Cloud 2024.x彻底移除了Sleuth,需要迁移到Micrometer Tracing:
spring-cloud-starter-sleuth依赖,替换为micrometer-tracing-bridge-braveTracer替换为Micrometer的TracerAPISpring Boot 3 + Spring Cloud 2024.x的组合,完成了Java技术栈向云原生架构的全面转型。从底层的JDK 17与Jakarta EE迁移,到上层的AOT原生镜像、虚拟线程、声明式HTTP客户端、标准化可观测性体系,每一项特性都直击云原生场景的核心痛点,让Java应用在容器化、Serverless场景下具备了与Go等原生云原生语言抗衡的能力。