Oracle ucp.jar应放Tomcat lib还是war包?如何解决重部署ResultSetMetaData缺失问题
解决方案
依赖配置调整(同时解决类加载错误与注解冲突)
- Oracle JDBC驱动
ojdbc.jar依旧放在$CATALINA_BASE/lib目录下,Maven中对应依赖的scope设置为provided,避免打进应用包。 - UCP连接池依赖
ucp.jar设置scope为runtime,通过Maven WAR插件打包时排除其中和ojdbc重复的冲突类:
<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-war-plugin</artifactId> <version>3.0.0</version> <configuration> <packagingExcludes> WEB-INF/lib/ucp.jar!/oracle/jdbc/logging/annotations/** </packagingExcludes> </configuration> </plugin>
- Spring配置UCP数据源时指定销毁方法,确保上下文关闭时主动释放连接资源:
<bean id="dataSource" class="oracle.ucp.jdbc.PoolDataSourceImpl" destroy-method="close"> <!-- 连接池其他配置 --> </bean>
如果是注解配置,对应添加@Bean(destroyMethod = "close")即可。
NoClassDefFoundError问题根因修复
调整后每个应用的UCP连接池由当前应用的类加载器独立加载,不会绑定之前部署版本的类加载器引用,新版本应用初始化连接池后调用ResultSetMetaData相关接口时,会使用当前应用的类加载器加载对应类,彻底避免类加载器销毁后引发的类找不到错误。
重部署内存泄漏修复
修改Tomcatconf/server.xml对应Host节点的配置,启用线程清理能力:
<Host name="localhost" appBase="webapps" unpackWARs="true" autoDeploy="true" clearReferencesStopThreads="true" clearReferencesStopTimerThreads="true"> <!-- 其他Host配置 --> </Host>
该配置会在应用实例下线时,主动停止该应用启动的所有未关闭的线程、定时器,直接解决ojdbc启动的Timer-0、BlockReleaser、InterruptTimer等线程残留导致的内存泄漏问题。
验证方案
- 部署第一版应用,分别调用简单查询和涉及
ResultSetMetaData的接口,确认功能正常 - 并行部署第二版应用,等待旧版本无活跃会话后自动下线
- 调用新版本所有接口,确认无
NoClassDefFoundError、ArrayStoreException异常,事务功能正常 - 多次重复部署操作,查看Tomcat日志无内存泄漏警告,通过JVM监控确认旧应用的类加载器已被正常GC回收
内容的提问来源于stack exchange,提问作者Kirill
相关产品推荐
相关产品推荐

