【问题标题】:Finding out who calls jvm shutdown hook找出谁调用了 jvm 关闭钩子
【发布时间】:2017-06-24 19:06:10
【问题描述】:

我有基于 Java 的 Windows 桌面应用程序。

我在我的应用程序中保留了 defaultuncaughtexceptionahandler 和 shutdown hook。

我有一些用户称为退出点,例如,用户点击退出,一些错误情况等。所有用户退出点都有适当的日志,随后是登录关闭挂钩。

现在,对于我的一位用户来说,应用程序会不时退出。这里用户没有调用任何用户出口点。打印关闭挂钩日志。 defaultuncaughtexception 处理程序没有异常。

我无法找到调用 system.exit 的人,因此无法找到 shutdown hook 。 我能以某种方式找到所谓的关机钩子或 system.exit () 吗? 打印关闭钩子让我认为这是正确的 jvm 关闭而不是突然关闭。

最好的问候, 索拉夫

【问题讨论】:

  • 抛出、捕获并记录异常。
  • 但是未捕获的异常处理程序不应该捕获未捕获的异常吗?...日志还显示了系统退出发生之前的不同情况
  • 什么?我说抓住它。
  • @DaveNewton 为什么你需要扔/接住它?只需创建异常并打印它的堆栈跟踪,或者更容易键入(但也一样),调用Thread.dumpStack()
  • @ErwinBolwidt 当然,这也很好。

标签: java jvm shutdown-hook


【解决方案1】:

如果你怀疑有人显式调用了System.exit(…)或类似的函数,你可以用SecurityManager拦截它:

System.setSecurityManager(new SecurityManager() {
    @Override
    public void checkExit(int status) {
        new Exception("exit attempt with return code "+status).printStackTrace();
    }
    // note that all dedicated check... methods delegate to the two below,
    // so overriding these is sufficient to enable all other actions
    @Override
    public void checkPermission(Permission perm, Object context) { }

    @Override
    public void checkPermission(Permission perm) { }
});

但是,这不会拦截由外部事件引起的关闭,例如 TERM 信号等。

【讨论】:

  • 非常感谢 Holger 的工作,但我的缺点是我必须完全扩展安全管理器以放松其他方法
  • 哦,我忘了那个方面。请参阅我的更新答案。
【解决方案2】:

如果您正在运行 OpenJDK / Oracle JDK,您可以注册一个“系统”关闭挂钩,该挂钩将转储已启动关闭进程的线程:

    sun.misc.SharedSecrets.getJavaLangAccess().registerShutdownHook(7, true,
            () -> {
                System.out.println(Thread.currentThread());
                new Exception("Who called me?").printStackTrace();
            });

这甚至适用于Ctrl+C 等外部事件。

【讨论】:

  • 我在 Spring Boot 应用程序的主要方法中尝试了您的示例代码。我会收到 2 个错误 1.“我已注册的插槽处的关闭挂钩”2.如果使用 i 值大于 10,则索引超出范围异常
猜你喜欢
  • 2011-05-07
  • 1970-01-01
  • 2011-04-15
  • 2012-11-20
  • 1970-01-01
  • 1970-01-01
  • 2021-04-02
  • 1970-01-01
相关资源
最近更新 更多