Java 11升级到Java17,以及升级到Spring Boot 3的过程
随着Spring Boot 3 (opens new window)在2022年11月发布,最低支持Java 17。
作为Java企业开发领域最具影响力的框架,Spring Boot 3的发布,也意味着Java 17必将慢慢普及开来。
Java 11升级到Java 17,以及升级到Spring Boot 3的过程,是Java开发者必须面对的问题。本文将对此进行简单的介绍。
# 为何升级Java 17
- 更高的性能,参考 How much faster is Java 17? (opens new window)
- 更好的安全性,参考 Java 17的增强伪随机数生成器
- 更好的开发体验和开发效率,参见 Java历代版本新特性 12-17部分
- 更好的生态支持,比如Spring Boot 3 (opens new window) 和 GraalVM Native Image (opens new window)
# Java 11升级到Java 17
首先,我们需要注意到已经删除的功能,包括:
- Nashorn JavaScript引擎。Java 15删除了Nashorn JavaScript引擎。如果您仍想使用引擎,则可以使用 nashorn-core 依赖项。
- 实验编译器。Java 17 删除了对 GraalVM 的实验性提前 (AOT) 和实时 (JIT) 编译器的支持,如 JEP 410 (opens new window) 文档中所述。
其次,我们需要对Java 12到Java 17的新特性有所了解,请参考上面的文章。
其中,值得关注的新特性有:
- Switch 表达式 (opens new window)
- ZGC (opens new window)
- 文本块 (opens new window)
- instanceOf 模式匹配 (opens new window)
- 记录类 (opens new window)
- 密封类 (opens new window)
- 隐藏类 (opens new window)
# Spring Boot 2.x升级到Spring Boot 3
首先,请查看 Spring Boot 3 迁移指南 (opens new window)。
其中的重点有以下几方面:
# 三方库升级
其中最主要的是Spring Framework 6 (opens new window)和 Spring Security 6 (opens new window)。
还有就是相关Jakarta EE的升级。
从Jakarta EE 9开始,javax包名已经改为jakarta。Spring Boot 3.0已经升级到Jakarta EE 10,因此,需要注意包名的变化。
主要是以下包名的变化:
- 迁移
javax.activation
包到jakarta.activation
- 迁移
javax.annotation
包到jakarta.annotation
- 迁移
javax.security.auth.message
包到jakarta.security.auth.message
- 迁移
javax.security.jacc
包到jakarta.security.jacc
- 迁移
javax.batch
包到jakarta.batch
- 迁移
javax.decorator
包到jakarta.decorator
- 迁移
javax.ejb
包到jakarta.ejb
- 迁移
javax.el
包到jakarta.el
- 迁移
javax.enterprise
包到jakarta.enterprise
- 迁移
javax.faces
包到jakarta.faces
- 迁移
javax.inject
包到jakarta.inject
- 迁移
javax.interceptor
包到jakarta.interceptor
- 迁移
javax.jms
包到jakarta.jms
- 迁移
javax.json
包到jakarta.json
- 迁移
javax.jws
包到jakarta.jws
- 迁移
javax.mail
包到jakarta.mail
- 迁移
javax.persistence
包到jakarta.persistence
- 迁移
javax.resource
包到jakarta.resource
- 迁移
javax.security.enterprise
包到jakarta.security.enterprise
- 迁移
javax.servlet
包到jakarta.servlet
- 迁移
javax.transaction
包到jakarta.transaction
- 迁移
javax.validation
包到jakarta.validation
- 迁移
javax.websocket
包到jakarta.websocket
- 迁移
javax.ws
包到jakarta.ws
- 迁移
javax.xml.bind
包到jakarta.xml.bind
- 迁移
javax.soap
包到jakarta.soap
- 迁移
javax.xml.ws
包到jakarta.xml.ws
相关的Maven依赖也会发生变化,查看 Maven Repository: jakarta (opens new window)
# 属性变化
在 Spring Boot 3.0 中,一些配置属性被重命名/删除,开发人员需要相应地更新它们的 application.properties/application.yml。
为了帮助你解决这个问题,Spring Boot 提供了一个 spring-boot-properties-migrator 模块。作为依赖项添加到项目后,这不仅会在启动时分析应用程序的环境和打印诊断,还会在运行时临时迁移属性。
您可以通过将以下内容添加到 Maven 来添加迁移器pom.xml:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-properties-migrator</artifactId>
<scope>runtime</scope>
</dependency>
完成迁移后,请确保从项目的依赖项中删除此模块。
你也可以在此页面 (opens new window)找到具体属性变化,进行手动替换。
# 自动配置文件
Spring Boot 2.7 引入了一个新 META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
文件,用于注册自动配置,同时保持与 spring.factories
注册的向后兼容性。
在Spring Boot 3中,删除了对在 中 spring.factories
注册自动配置的支持,取而代之的是导入文件。
也就是说从 Spring Boot 3 开始,必须使用 META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
进行导入,以前的 spring.factories
导入方式将失效
# 尾部斜杠匹配
从 Spring Framework 6.0 开始,尾部斜杠匹配配置选项已被弃用,其默认值设置为 false .这意味着以前,以下控制器将同时匹配“GET /some/greeting”和“GET /some/greeting/”:
@RestController
public class MyController {
@GetMapping("/some/greeting")
public String greeting() {
return "Hello";
}
}
可以通过以下方式更改默认值:
@Configuration
public class WebConfiguration implements WebMvcConfigurer {
@Override
public void configurePathMatch(PathMatchConfigurer configurer) {
configurer.setUseTrailingSlashMatch(true);
}
}
# 删除了Elasticsearch’s high-level REST client
Elasticsearch 8.x开始,不支持Elasticsearch’s high-level REST client,因此Spring Boot 3.0删除了对其的支持。
请查看high-level REST client迁移指南 (opens new window) 了解如何迁移到新的Java REST客户端。
如果项目中去除RestHighLevelClient太麻烦,则可以通过添加如下配置来保留RestHighLevelClient:
@Configuration
@ConditionalOnProperty(prefix = "spring.elasticsearch", name = "uris")
public static class RestHighLevelClientConfig {
/**
* ElasticSearch客户端
*
* @param properties 属性
* @return {@link RestHighLevelClient}
*/
@Bean
@ConditionalOnMissingBean(RestHighLevelClient.class)
public RestHighLevelClient restHighLevelClient(ElasticsearchProperties properties) {
RestClientBuilder builder = RestClient.builder(properties.getUris().stream().map(HttpHost::create).toArray(HttpHost[]::new));
PropertyMapper map = PropertyMapper.get();
map.from(properties.getUsername()).whenHasText().to((username) -> {
CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
Credentials credentials = new UsernamePasswordCredentials(properties.getUsername(), properties.getPassword());
credentialsProvider.setCredentials(AuthScope.ANY, credentials);
builder.setHttpClientConfigCallback((httpClientBuilder) -> httpClientBuilder.setDefaultCredentialsProvider(credentialsProvider));
});
return new RestHighLevelClient(builder);
}
}
# dubbo框架的升级
dubbo 3.2 (opens new window) 开始对Spring Boot 3进行支持,所以需要升级dubbo版本。
参考 2.x 升级至 3.x (opens new window)。
# jasypt-spring-boot的升级
需要注意的是,jasypt-spring-boot 3.x 基于密码的默认配置 (opens new window)发生了变化。
为了与2.x版本的兼容性,你可以手动注入jasyptStringEncryptor
,且属性与原先一致,并把org.jasypt.salt.NoOpIVGenerator
改为org.jasypt.iv.NoIvGenerator
。
@Bean("jasyptStringEncryptor")
public StringEncryptor stringEncryptor(@Value("${jasypt.encryptor.password}") String password) {
PooledPBEStringEncryptor encryptor = new PooledPBEStringEncryptor();
SimpleStringPBEConfig config = new SimpleStringPBEConfig();
config.setPassword(password);
config.setAlgorithm("PBEWithMD5AndDES");
config.setKeyObtentionIterations("1000");
config.setPoolSize("1");
config.setProviderName("SunJCE");
config.setSaltGeneratorClassName("org.jasypt.salt.RandomSaltGenerator");
config.setIvGeneratorClassName("org.jasypt.iv.NoIvGenerator");
config.setStringOutputType("base64");
encryptor.setConfig(config);
return encryptor;
}
# sentinel的升级
主要是适配duboo 3:
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-apache-dubbo3-adapter</artifactId>
<version>x.y.z</version>
</dependency>
对于Spring Boot 3,sentinel官网还没有发布对应的版本,你可以fork官方项目 (opens new window),把servlet迁移到Jakarta EE包名,然后发布到自己的私服。
其实对于一些三方包,可能官方还没有发布对应的Spring Boot 3版本支持,都可以暂时采用上面的方式。 比如 mqtt-spring-boot-starter (opens new window)。
# Springfox迁移到Spring Doc 2
Springfox已经不再维护,可以使用Spring Doc 2 (opens new window)代替它。
迁移文档:Migrating from SpringFox (opens new window)
# Thymeleaf模板引擎的升级
Spring Boot 3将Thymeleaf的依赖升级到3.1,参考 Thymeleaf 3.1迁移指南 (opens new window)。
其中最重要的变化是:
不再支持通过web-API提供的表达式实用对象。
在此版本中,不再提供用于表达式的#request、#response、#session和#servletContext对象。先前版本中,这些对象可以用于在Thymeleaf模板中进行表达式计算和操作,但在3.1版本中被移除了。
所以如果你的thymeleaf模板中使用了这些对象,需要进行修改。
比如原先在页面中可以直接访问servletContext
中的属性:${#servletContext.getAttribute('ctx')}
。现在则需要从Controller中传递这些属性到模板中:
@GetMapping("/index")
public String index(HttpServletRequest request, Model model) {
model.addAttribute("ctx", request.getServletContext().getAttribute("ctx"));
return "index";
}
页面中使用ctx属性:
<link th:href="${ctx}+'/css/base.css'" rel="stylesheet" type="text/css">
# 总结
更高的性能,更好的安全性,更好的开发体验和开发效率,更好的生态支持。Java 17与Spring Boot 3你值得拥有!
祝你变得更强!