6

当我第一次使用 Apache daemon 为 Windows 开发 Java 服务时,我使用了JVM我非常喜欢的模式。您指定您的类和 start\stop (静态)方法。但是对于 Linux,Jsvc 看起来并没有相同的选项。我真的很想知道为什么?!

无论如何,如果我要使用 Linux 的 init 系统,我正在尝试找到一种类似的方法来完成相同的行为,即无论如何启动应用程序但要停止它,我将不得不调用一个类中的方法.

我的问题是,在 jar 启动后,我如何使用 JVM 库或其他任何东西来调用我的应用程序中的方法(这将尝试优雅地停止我的应用程序)。

另一个问题,如果应用程序启动并且该应用程序具有静态方法,如果我使用java命令行在其中运行一个main方法,如果那是应用程序类,并且该main方法static将在我所在的类中调用另一个静态方法想要发出终止信号,是否会在同一个 JVM 中调用?

4

2 回答 2

8

为什么不ShutdownHook向您的应用程序添加一个?

关闭挂钩只是一个已初始化但未启动的线程。当虚拟机开始其关闭序列时,它将以某种未指定的顺序启动所有已注册的关闭挂钩并让它们同时运行。当所有钩子都完成后,如果 finalization-on-exit 已启用,它将运行所有未调用的终结器。最后,虚拟机将停止。请注意,在关闭序列期间,守护线程将继续运行,如果通过调用 exit 方法启动关闭,非守护线程也将继续运行。

这将允许您的 jar 在关闭之前正常终止:

public class ShutdownHookDemo {
    public void start() {
        System.out.println("Demo");
        ShutdownHook shutdownHook = new ShutdownHook();
        Runtime.getRuntime().addShutdownHook(shutdownHook);
    }

    public static void main(String[] args) {
        ShutdownHookDemo demo = new ShutdownHookDemo();
        demo.start();
        try {
            System.in.read();
        }
        catch(Exception e) {
        }
    }
}

class ShutdownHook extends Thread {
    public void run() {
        System.out.println("Shutting down");
        //terminate all other stuff for the application before it exits
    }

}

重要的是要注意

关闭挂钩在以下情况下运行:

  • 程序正常存在。例如,调用 System.exit(),或者最后一个非守护线程退出。
  • 虚拟机被终止。例如 CTRL-C。这对应于 kill -SIGTERM pid 或
  • 在 Unix 系统上杀死 -15 pid。

在以下情况下,关闭挂钩将不会运行:

  • 虚拟机中止
  • SIGKILL 信号被发送到 Unix 系统上的虚拟机进程。例如 kill -SIGKILL pid 或 kill -9 pid
  • TerminateProcess 调用被发送到 Windows 系统上的进程。

或者,如果您必须使用它来调用类中的方法:

public class ReflectionDemo {

  public void print(String str, int value) {
    System.out.println(str);
    System.out.println(value);
  }

  public static int getNumber() { return 42; }

  public static void main(String[] args) throws Exception {
    Class<?> clazz = ReflectionDemo.class;//class name goes here
    // static call
    Method getNumber = clazz.getMethod("getNumber");
    int i = (Integer) getNumber.invoke(null /* static */);
    // instance call
    Constructor<?> ctor = clazz.getConstructor();
    Object instance = ctor.newInstance();
    Method print = clazz.getMethod("print", String.class, Integer.TYPE);
    print.invoke(instance, "Hello, World!", i);
  }
}

并动态加载一个类:

ClassLoader loader = URLClassLoader.newInstance(
    new URL[] { yourURL },
    getClass().getClassLoader()
);
Class<?> clazz = Class.forName("mypackage.MyClass", true, loader);
Class<? extends Runnable> runClass = clazz.asSubclass(Runnable.class);

参考:

于 2012-08-04T17:57:30.717 回答
2

基本上,在 JVM 之间调用的唯一方法是通过使用Sockets,直接或通过基于它的实现,例如RMI

您可能会撒谎以查看http://www.javaworld.com/javaqa/2000-03/03-qa-0324-ipc.html以获取更多信息

于 2012-08-04T20:58:39.203 回答