Jetty应用关闭时UCP在关闭钩子执行前自动关闭,求解决及原因
问题原因与解决方案
核心原因
- UCP默认关闭钩子:Oracle UCP会自动向JVM注册ShutdownHook,这个钩子的触发优先级可能高于你自定义的关闭逻辑或Jetty的生命周期回调,导致UCP提前关闭。
- Jetty组件生命周期顺序:如果UCP连接池绑定到Jetty的某个组件(如WebAppContext)上,Jetty在销毁组件时会触发相关资源释放,可能提前触发UCP的关闭流程。
解决办法
1. 禁用UCP自动关闭钩子
在初始化UCP连接池时,关闭其内置的ShutdownHook,将关闭控制权完全交给你的代码:
PoolDataSource ucpPool = PoolDataSourceFactory.getPoolDataSource(); // 禁用UCP自带的关闭钩子 ucpPool.setShutdownHookEnabled(false); // 其他连接池配置...
2. 绑定Jetty生命周期执行自定义逻辑
利用Jetty的LifeCycle.Listener,在Jetty开始关闭时执行预销毁操作,再显式关闭UCP连接池:
public class AppShutdownListener implements LifeCycle.Listener { private final PoolDataSource ucpPool; public AppShutdownListener(PoolDataSource ucpPool) { this.ucpPool = ucpPool; } @Override public void lifeCycleStopping(LifeCycle event) { // 执行你的预销毁操作:比如收尾事务、清理临时数据等 runPreDestroyTasks(); // 显式关闭UCP连接池 try { ucpPool.close(); } catch (SQLException e) { // 根据业务需求处理关闭异常 e.printStackTrace(); } } private void runPreDestroyTasks() { // 自定义预销毁逻辑实现 } }
将监听器添加到Jetty Server实例:
Server jettyServer = new Server(8080); // 初始化UCP连接池(已禁用自动关闭钩子) PoolDataSource ucpPool = initUcpPool(); // 注册监听器 jettyServer.addLifeCycleListener(new AppShutdownListener(ucpPool));
3. Web应用场景:绑定ServletContext生命周期
如果是Web应用,可通过ServletContextListener在Web应用销毁时执行逻辑:
public class AppContextListener implements ServletContextListener { private PoolDataSource ucpPool; @Override public void contextInitialized(ServletContextEvent sce) { // 初始化UCP连接池并禁用自动关闭钩子 ucpPool = PoolDataSourceFactory.getPoolDataSource(); ucpPool.setShutdownHookEnabled(false); sce.getServletContext().setAttribute("ucpPool", ucpPool); } @Override public void contextDestroyed(ServletContextEvent sce) { // 执行预销毁操作 runPreDestroyTasks(); // 关闭连接池 try { ucpPool.close(); } catch (SQLException e) { e.printStackTrace(); } } private void runPreDestroyTasks() { // 预销毁逻辑 } }
在web.xml中注册该监听器:
<listener> <listener-class>com.yourpackage.AppContextListener</listener-class> </listener>
内容的提问来源于stack exchange,提问作者Rajat
相关产品推荐
相关产品推荐

