1. 项目背景与升级必要性
作为Java开发者,我们正处在一个技术栈迭代的关键节点。Oracle官方已于2019年停止对JDK8的公共更新支持,而Spring Boot 3.x系列更是强制要求JDK17作为最低版本。这次升级不仅是版本号的变更,更代表着从Java EE到Jakarta EE的范式转移。
我最近刚完成一个中型电商系统的升级工作,从原来的JDK8+Spring Boot 2.6环境迁移到JDK17+Spring Boot 3.1。整个过程踩了不少坑,也积累了些实战经验。下面就把这次升级的核心要点和避坑指南完整分享给大家。
2. 环境准备与兼容性检查
2.1 JDK17安装与多版本管理
建议使用SDKMAN工具管理多版本JDK:
# 安装SDKMAN curl -s "https://get.sdkman.io" | bash source "$HOME/.sdkman/bin/sdkman-init.sh" # 安装JDK17 sdk install java 17.0.7-tem重要提示:生产环境推荐使用Temurin发行版(原AdoptOpenJDK),避免Oracle JDK的许可问题。实测Temurin在Linux服务器上的内存占用比Oracle JDK低15%左右。
2.2 依赖库兼容性扫描
使用Spring Boot提供的迁移工具检查依赖:
mvn spring-boot:validate -Dspring-boot.version=3.1.0常见不兼容依赖包括:
- javax.* 包(需替换为jakarta.*)
- Spring Cloud旧版本(需升级到2022.x+)
- 老版本的Hibernate Validator
3. 代码改造关键点
3.1 Jakarta EE包路径变更
所有javax.导入需要替换为jakarta.,例如:
// 修改前 import javax.servlet.http.HttpServletRequest; import javax.persistence.Entity; // 修改后 import jakarta.servlet.http.HttpServletRequest; import jakarta.persistence.Entity;推荐使用IntelliJ IDEA的批量替换功能(Ctrl+Shift+R),配合以下正则表达式:
import javax\.(.*); → import jakarta.$1;3.2 Spring Security 6.x配置变更
旧版配置:
@Configuration public class SecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http.authorizeRequests() .antMatchers("/public/**").permitAll() .anyRequest().authenticated(); } }新版Lambda风格配置:
@Configuration public class SecurityConfig { @Bean public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { return http .authorizeHttpRequests(auth -> auth .requestMatchers("/public/**").permitAll() .anyRequest().authenticated() ) .build(); } }3.3 响应式编程适配
如果项目使用WebFlux,注意以下变更:
- RouterFunctions的静态方法路径从
org.springframework.web.reactive.function.server移动到org.springframework.web.servlet.function - ServerRequest/ServerResponse的包路径变更为jakarta.*
4. 构建配置调整
4.1 Maven配置示例
<properties> <java.version>17</java.version> <spring-boot.version>3.1.0</spring-boot.version> </properties> <dependencies> <!-- 注意jakarta依赖 --> <dependency> <groupId>jakarta.servlet</groupId> <artifactId>jakarta.servlet-api</artifactId> <version>6.0.0</version> <scope>provided</scope> </dependency> </dependencies>4.2 Gradle配置要点
java { toolchain { languageVersion = JavaLanguageVersion.of(17) } } dependencies { implementation platform("org.springframework.boot:spring-boot-dependencies:3.1.0") // 其他依赖... }5. 测试与验证策略
5.1 单元测试适配
JUnit 5已成为Spring Boot 3.x的默认测试框架。注意:
- 移除
@RunWith(SpringRunner.class) - 使用
@SpringBootTest时默认加载Web环境改为MOCK
@SpringBootTest(webEnvironment = WebEnvironment.MOCK) class OrderServiceTest { @Test void shouldCreateOrder() { // 测试逻辑 } }5.2 集成测试要点
使用Testcontainers进行兼容性验证:
@Testcontainers class PaymentIntegrationTest { @Container static PostgreSQLContainer<?> postgres = new PostgreSQLContainer<>("postgres:15"); @DynamicPropertySource static void configureProperties(DynamicPropertyRegistry registry) { registry.add("spring.datasource.url", postgres::getJdbcUrl); } }6. 性能调优建议
升级后建议关注以下指标:
- GC日志分析:JDK17的ZGC性能提升明显,建议配置:
-XX:+UseZGC -Xmx4g -Xlog:gc* - 启动时间优化:Spring Boot 3.x的AOT模式可提升30%启动速度
mvn spring-boot:build-image
7. 常见问题解决方案
7.1 ClassNotFoundException问题
典型错误:
java.lang.ClassNotFoundException: javax.servlet.Filter解决方案:
- 检查是否遗漏jakarta依赖
- 清理IDE缓存和target目录
- 使用
mvn dependency:tree检查冲突
7.2 数据库连接异常
Hibernate 6.x的方言配置变更:
spring: jpa: properties: hibernate.dialect: org.hibernate.dialect.MySQL8Dialect7.3 监控端点调整
Actuator端点路径变更:
/actuator/health→/health(需配置management.endpoints.web.base-path)- 默认只暴露health和info端点
安全配置示例:
@Bean public SecurityFilterChain actuatorSecurity(HttpSecurity http) throws Exception { return http .securityMatcher("/actuator/**") .authorizeHttpRequests(auth -> auth.anyRequest().hasRole("ACTUATOR")) .httpBasic(withDefaults()) .build(); }8. 回滚策略设计
建议采用蓝绿部署方案:
- 新旧环境并行运行
- 通过负载均衡逐步切流
- 保留旧环境至少48小时
- 关键指标监控:
- 错误率
- 响应时间P99
- JVM内存使用率
我在实际升级过程中发现,最大的挑战往往来自第三方库的兼容性问题。建议先在一个独立分支进行验证,使用dependency-check-maven插件定期扫描漏洞。对于必须使用的老旧库,可以考虑用maven-shade-plugin进行relocation处理。