JDK版本导致ClassNotFoundException
## 简介 > 一次踩坑记录。 > > 本地安装多个版本的JDK时,如果不指定版本启动Java程序,
渲染中...
## 简介
> 一次踩坑记录。
>
> 本地安装多个版本的JDK时,如果不指定版本启动Java程序,我的本地是默认使用高版本的,所以出现了预料之外的错误。
<!-- more -->
## 报错示例
- 报错场景:使用`JWT`工具生成token时,需要使用`DatatypeConverter`类进行一些数据处理。
```
java.lang.ClassNotFoundException: javax.xml.bind.DatatypeConverter
at java.base/java.net.URLClassLoader.findClass(URLClassLoader.java:445)
at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:587)
at org.springframework.boot.loader.LaunchedURLClassLoader.loadClass(LaunchedURLClassLoader.java:94)
at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:520)
at com.hlkj.dncc.util.JwtHelper.createJwt(JwtHelper.java:48)
at com.hlkj.dncc.service.impl.AccountServiceImpl.login(AccountServiceImpl.java:89)
at com.hlkj.dncc.controller.AccountController.login(AccountController.java:37)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:568)
at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:190)
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:138)
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:105)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:892)
```
## 报错原因
我在开发时使用的是`JDK8`环境,但是我本地安装了多个版本的JDK,包括`JDK11`、`JDK17`。当我将代码打包成jar包后,在本地试运行,他默认使用的不是`JDK8`,而是`JDK17`。
- 检查JDK版本:cmd窗口执行`java -version`,输出如下信息
```shell
java version "17.0.5" 2022-10-18 LTS
Java(TM) SE Runtime Environment (build 17.0.5+9-LTS-191)
Java HotSpot(TM) 64-Bit Server VM (build 17.0.5+9-LTS-191, mixed mode, sharing)
```
> 未知疑问:正常来说,这里应该是环境变量配置的JDK版本才对,刚开始的解决思路也是去修改环境变量为`JDK8`,但是当我去修改时,发现环境变量配置的是`JDK11`,这就让我呆住了。
>
> 所以我也没有去修改环境变量,而是通过设置临时环境变量的方式来解决这个问题。
## 报错解决
> PS:如果你可以跳过本地试运行这一步,不解决这个问题也无所谓,直接到正常的服务器上试运行即可。
- 设置临时环境变量。注意其中`C:\Program Files\Java\jdk1.8.0_281\bin`是你想要的JDK版本的可执行文件路径,根据自身实际情况配置。
```shell
set PATH=C:\Program Files\Java\jdk1.8.0_281\bin
```
- 配置完成后,再次查看java版本`java -version`,可以发现已经切换到`JDK8`,此时正常运行程序再检查是否还会报错即可。
```shell
java version "1.8.0_281"
Java(TM) SE Runtime Environment (build 1.8.0_281-b09)
Java HotSpot(TM) 64-Bit Server VM (build 25.281-b09, mixed mode)
```
## 问题排查思路总结
如果你知道一个知识点,这个问题可能很好解决,那就是:**`javax.xml.bind`包,在`JDK11`以后,已经从jdk中完全移除。** 详情可阅读官方发行说明:[JDK 11 Release Notes](https://www.oracle.com/java/technologies/javase/11-relnote-issues.html#JDK-8190378)
如果你不知道这个知识点,你可以按照常规思路排查:
1. 首先找到包路径`javax.xml.bind.DatatypeConverter`
2. 如果是其他框架依赖下的类,如`org.springframework.beans`等,可以检查是否存在依赖冲突。(一般是存在相同名,但版本不同的依赖被引用了)
3. 如果不是框架依赖下的类,如本次示例中的`javax.xml.bind.DatatypeConverter`,看起来就是JDK应该自带的相关类,那么就可以检查是否是JDK版本或环境变量的问题。
END
评论
登录后查看和发表评论
前往登录