最近写了一个定时触发java进程的程序,采用的是spring处理的,但是运行在生产环境上以后现场运维测试发现每天定时任务的时候只有第一天触发的时候可以使用,但是后边的都有问题,于是就进入生产环境查看,发现我们的java进程并没有被完全杀掉,附上代码
try {
context = new ClassPathXmlApplicationContext(PATH);
context.registerShutdownHook();
context.start();
PropertiesUtil.load("batch.properties");
LOG.info("【处理】。。。。");
GetRecordDetail recordDetail=context.getBean(GetRecordDetail.class);
recordDetail.recordFromZX();
}catch(Exception e) {
LOG.error("【错误:"+e.getMessage()+"】",e);
}finally{
context.close();
}
百思不得其解,后来经过查资料发现,我们多余写了一个钩子,context.registerShutdownHook();源码如下
/** * Register a shutdown hook with the JVM runtime, closing this context * on JVM shutdown unless it has already been closed at that time. *
Delegates to {@code doClose()} for the actual closing procedure.
* @see Runtime#addShutdownHook
* @see #close()
* @see #doClose()
*/
@Override
public void registerShutdownHook() {
if (this.shutdownHook == null) {
// No shutdown hook registered yet.
this.shutdownHook = new Thread() {
@Override
public void run() {
doClose();
}
};
Runtime.getRuntime().addShutdownHook(this.shutdownHook);
}
}
从源码可以看出,这是调用了jvm的关闭钩子,于是翻阅jvm的关闭钩子可以发现,正常情况下关闭钩子是为了更优雅的去关闭清理一些资源,但是如果说在只想jvm关闭的时候钩子还在运行,那么虽然看似进程已经关闭了,其实钩子还没有关闭。这就导致没有正常关闭进程,从而出现上边所说的问题。
解决办法:注释掉注册钩子事件。问题完美解决,但是我们的初衷没有达到,后续还会继续跟进研究。