升级Spring Boot 3与JDK21后RestTemplate遇SSL问题
JDK 21 + Spring Boot 3.2.2 升级后RestTemplate SSL握手问题解答
问题1:为何新版本JDK默认不再使用系统证书?
- JDK 11及更早版本的OpenJDK,在Linux等平台会默认合并系统根证书(如
/etc/ssl/certs下的证书)到JDK自带的cacerts信任库,或自动加载系统信任库。 - 从JDK 17开始(含JDK 21),OpenJDK调整了信任库加载逻辑:默认仅使用JDK安装目录下
lib/security/cacerts文件内的证书,不再自动包含系统层面安装的证书。 - 你的测试机器上的目标证书仅安装在系统证书库,未导入JDK 21的
cacerts,因此JDK 21无法识别该证书,导致PKIX路径构建失败。
问题2:为何配置信任库会引发密钥库异常?
- 你配置的
server.ssl.trust-store和server.ssl.trust-store-password是用于当前Spring Boot服务作为HTTPS服务器的配置,作用是指定服务端信任的客户端证书库,和RestTemplate作为HTTP客户端的SSL配置完全无关。 - 当你设置了
server.ssl.trust-store但未配置server.ssl.key-store(服务端自身HTTPS证书的密钥库)时,Spring Boot会默认尝试加载/root/.keystore作为服务端密钥库,该文件不存在就会抛出找不到文件的异常。 - 正确做法是单独配置RestTemplate的客户端SSL上下文,指定自定义信任库,而非修改服务端的SSL配置。
快速修复方案
解决系统证书识别问题:将目标证书导入JDK 21的
cacerts文件,命令示例:keytool -importcert -file /path/to/your/cert.crt -alias your-cert-alias -keystore $JAVA_HOME/lib/security/cacerts -storepass changeit(JDK默认
cacerts密码为changeit)正确配置RestTemplate的客户端SSL:
@Bean public RestTemplate restTemplate() throws Exception { KeyStore trustStore = KeyStore.getInstance("PKCS12"); try (InputStream is = getClass().getResourceAsStream("/truststore.p12")) { trustStore.load(is, "some-password".toCharArray()); } SSLContext sslContext = SSLContexts.custom() .loadTrustMaterial(trustStore, null) .build(); HttpClient httpClient = HttpClients.custom() .setSSLContext(sslContext) .build(); HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory(httpClient); return new RestTemplate(factory); }同时删除
server.ssl.trust-store相关配置,避免服务端SSL配置冲突。
内容的提问来源于stack exchange,提问作者Marian Klüspies
相关产品推荐
相关产品推荐

