system.exit和finally

由于工程需要,需要起一个CT任务。在CT任务的时候,起的是一个main方法。在结束的时候调用了System.exit(0)。但是发现调用System.exit的时候,无论是finally还是Spring的@PreDestroy注解的方法都没有执行。所以去查了相应的资料。

How does Java's System.exit() work with try/catch/finally blocks
可见System.exit是直接调用了关闭Jvm的方法,自然不会调用Spring的BeanFactory的关闭方法。
我们通过源码可以更加直观的观察到其运行方法:

public static void exit(int status) {
    Runtime.getRuntime().exit(status);
}

从方法的注释中可以看出此方法是结束当前正在运行的Java虚拟机,这个status表示退出的状态码,非零表示异常终止。注意:不管status为何值程序都会退出,和return 相比有不同的是:return是回到上一层,而System.exit(status)是回到最上层。
由以上分析可知,在使用System.exit的时候并不会调用finally中的方法,更别提Spring的注解@PreDestroy。
如果希望上面的情况能够正常工作,需要如下的进行:
获取ApplicationContext。在AbstractApplicationContext中有一个方法方法close()可以调用。所以可以如下进行:

public static void shutDown() {
        LOGGER.info("start to shut down application context");
        if (null != ac) {
            if (ac instanceof AbstractApplicationContext) {
                AbstractApplicationContext beanFactory = (AbstractApplicationContext) ac;
                beanFactory.close();
            }
        }
    }

同时将System.exit(0)删除即可。
如同上面讲的,除了采用调用AbstractApplicationContext的close()方法外,还也可以使用

((AbstractApplicationContext)appCtx).registerShutdownHook();

讨论参考how-to-close-a-spring-applicationcontext
来将applicationContext注册到jvm关闭的钩子上,这样在jvm关闭的时候就会自动调用AbstractApplicationContext的doClose方法。
这部分的内容可以参考源码来进一步了解:

@Override
    public void registerShutdownHook() {
        if (this.shutdownHook == null) {
            // No shutdown hook registered yet.
            this.shutdownHook = new Thread() {
                @Override
                public void run() {
                    synchronized (startupShutdownMonitor) {
                        doClose();
                    }
                }
            };
            Runtime.getRuntime().addShutdownHook(this.shutdownHook);
        }
    }

最本质的内容就是调用了Runtime.getRuntime().addShutdownHook(Thread hook);

你可能感兴趣的:(system.exit和finally)