错误
最近网站因为 spring-jdbc 依赖版本低出现的 NoClassDefFoundError 问题, 问题情况是:该依赖已经用了很久了,一直是可以正常使用的。突然间就出现该问题,导致系统崩溃。 下面是错误信息
2019-06-04 19:41:26.857 ERROR 32732 — [nio-9013-exec-2] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Handler dispatch failed; nested exception is java.lang.NoClassDefFoundError: org/springframework/core/JdkVersion] with root cause
java.lang.NoClassDefFoundError: org/springframework/core/JdkVersion
at org.springframework.jdbc.support.SQLErrorCodeSQLExceptionTranslator.(SQLErrorCodeSQLExceptionTranslator.java:85) ~[spring-jdbc-3.2.5.RELEASE.jar!/:3.2.5.RELEASE]
at org.springframework.jdbc.support.SQLErrorCodeSQLExceptionTranslator.(SQLErrorCodeSQLExceptionTranslator.java:102) ~[spring-jdbc-3.2.5.RELEASE.jar!/:3.2.5.RELEASE]
at org.mybatis.spring.MyBatisExceptionTranslator.initExceptionTranslator(MyBatisExceptionTranslator.java:83) ~[mybatis-spring-1.2.0.jar!/:1.2.0]
at org.mybatis.spring.MyBatisExceptionTranslator.translateExceptionIfPossible(MyBatisExceptionTranslator.java:70) ~[mybatis-spring-1.2.0.jar!/:1.2.0]
at org.mybatis.spring.SqlSessionTemplate
S
q
l
S
e
s
s
i
o
n
I
n
t
e
r
c
e
p
t
o
r
.
i
n
v
o
k
e
(
S
q
l
S
e
s
s
i
o
n
T
e
m
p
l
a
t
e
.
j
a
v
a
:
364
)
[
m
y
b
a
t
i
s
−
s
p
r
i
n
g
−
1.2.0.
j
a
r
!
/
:
1.2.0
]
a
t
c
o
m
.
s
u
n
.
p
r
o
x
y
.
SqlSessionInterceptor.invoke(SqlSessionTemplate.java:364) ~[mybatis-spring-1.2.0.jar!/:1.2.0] at com.sun.proxy.
SqlSessionInterceptor.invoke(SqlSessionTemplate.java:364) [mybatis−spring−1.2.0.jar!/:1.2.0]atcom.sun.proxy.Proxy47.update(Unknown Source) ~[na:na]
at org.mybatis.spring.SqlSessionTemplate.update(SqlSessionTemplate.java:250) ~[mybatis-spring-1.2.0.jar!/:1.2.0]
at org.apache.ibatis.binding.MapperMethod.execute(MapperMethod.java:82) ~[mybatis-3.1.1.jar!/:3.1.1]
at org.apache.ibatis.binding.MapperProxy.invoke(MapperProxy.java:40) ~[mybatis-3.1.1.jar!/:3.1.1]
at com.sun.proxy.$Proxy87.updateOnlineInfo(Unknown Source) ~[na:na]
at com.bricdata.server.service.impl.UsCustomerServiceImpl.notifyService(UsCustomerServiceImpl.java:375) ~[classes!/:0.0.1-SNAPSHOT]
at com.bricdata.server.action.HeartbeatController.notify(HeartbeatController.java:42) ~[classes!/:0.0.1-SNAPSHOT]
at sun.reflect.GeneratedMethodAccessor83.invoke(Unknown Source) ~[na:na]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_131]
at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_131]
at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:189) ~[spring-web-5.1.5.RELEASE.jar!/:5.1.5.RELEASE]
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:138) ~[spring-web-5.1.5.RELEASE.jar!/:5.1.5.RELEASE]
at
问题排查
java.lang.NoClassDefFoundError: org/springframework/core/JdkVersion 从这个问题可以定位到 是jar包的问题, spring jdbc 是 spring-jdbc-3.2.5.RELEASE.jar ,spring 的其他jar 包版本是 5.1.5.RELEASE ,可以定位出是jdbc 的版本问题,
出现这个问题 是因为以前是正常可用的, 突然出现这个问题,所以排查出这个问题的根源所在
排查步骤:
- SQLErrorCodeSQLExceptionTranslator.java:85 进入该类 该行,发现JdkVersion 没有该类 ,此时可以定位出是jar 包的问题
public SQLErrorCodeSQLExceptionTranslator() {
if (JdkVersion.getMajorJavaVersion() >= JdkVersion.JAVA_16) {
setFallbackTranslator(new SQLExceptionSubclassTranslator());
}else {
setFallbackTranslator(new SQLStateSQLExceptionTranslator());
}
}
- 为什么以前没有报错,突然就报错了呢,继续查看该问题的调用栈信息,最终 在
JdbcTemplate
中找到调用信息
public <T> T execute(ConnectionCallback<T> action) throws DataAccessException {
Assert.notNull(action, "Callback object must not be null");
Connection con = DataSourceUtils.getConnection(getDataSource());
try {
Connection conToUse = con;
if (this.nativeJdbcExtractor != null) {
// Extract native JDBC Connection, castable to OracleConnection or the like.
conToUse = this.nativeJdbcExtractor.getNativeConnection(con);
}
else {
// Create close-suppressing Connection proxy, also preparing returned Statements.
conToUse = createConnectionProxy(con);
}
return action.doInConnection(conToUse);
}
catch (SQLException ex) {
// Release Connection early, to avoid potential connection pool deadlock
// in the case when the exception translator hasn't been initialized yet.
DataSourceUtils.releaseConnection(con, getDataSource());
con = null;
throw getExceptionTranslator().translate("ConnectionCallback", getSql(action), ex);
}
finally {
DataSourceUtils.releaseConnection(con, getDataSource());
}
}
原因是在 执行方法的时候, 由于数据源连接不上或死锁 会 throw Exception ,在异常处理的过程中,用到了JDKVersion 的类,所以会出现上面的问题