java - 调用批处理运行jar的方法

标签 java function batch-file jar program-entry-point

我有一个Java应用程序,它的主函数是从带有2个参数的批处理文件中调用的。 现在我想将另一对参数传递给同一个应用程序,而不是打开另一个实例。 是否可以从外部调用正在运行的 jar 文件的主函数(或任何其他函数)?

感谢您的帮助!

最佳答案

正如我在评论中提到的,您可能应该使用 JMX 来执行此操作。

JMX 允许您从程序中公开“管理 bean”,然后可以远程调用它们。

让我们从一个简单的例子开始:

private static class Consumer implements Runnable {

    private final BlockingQueue<String> blockingQueue;

    public Consumer(BlockingQueue<String> blockingQueue) {
        this.blockingQueue = blockingQueue;
    }

    @Override
    public void run() {
        while (true) {
            try {
                final String s = blockingQueue.take();
                System.out.println(s);
                if ("EXIT".equalsIgnoreCase(s)) {
                    return;
                }
            } catch (InterruptedException ex) {
                return;
            }
        }
    }
}

public static interface ProducerMBean {

    void add(String string);

    String contents();
}

private static class Producer implements ProducerMBean {

    private final BlockingQueue<String> blockingQueue;

    public Producer(BlockingQueue<String> blockingQueue) {
        this.blockingQueue = blockingQueue;
    }

    @Override
    public void add(String string) {
        blockingQueue.add(string);
    }

    @Override
    public String contents() {
        return blockingQueue.toString();
    }
}

public static void main(String[] args) throws Exception {
    final ExecutorService executorService = Executors.newSingleThreadExecutor();
    final BlockingQueue<String> blockingQueue = new LinkedBlockingQueue<>();
    executorService.submit(new Consumer(blockingQueue));
    final Producer producer = new Producer(blockingQueue);
    final ObjectName name = new ObjectName("com.example.producer:type=SomeUnqiueName");
    ManagementFactory.getPlatformMBeanServer().registerMBean((ProducerMBean) producer, name);
    executorService.shutdown();
}

这是一种扭曲的生产者/消费者模式。

消费者太无聊了,它吐槽String如果队列被中断或收到String,则从队列中退出并退出“导出”。另一方面,制作人则更有趣一些。

首先我们有interface ProducerMBean ,这是一个public interface正如我们稍后将看到的,它充当面向外的交互点。然后我们有一个 Producer其中implements ProducerMBean ,它只是将内容添加到 BlockingQueue 。这里值得注意的是,所有这些必须是线程安全的,否则您将遇到 JMX 线程将您的方法异步插入到应用程序线程的问题。

然后,我们向平台注册我们的 MBean(管理 bean),这会公开 interface到外面会;我们需要小心我们公开的内容,因为我们公开的任何内容都可以被调用。 ObjectName 的格式是 <folder>:type=<name> ,稍后你就会明白我的意思。

现在,当应用程序启动时,它就像预期的那样挂起。为了发送Strings我们需要打开 jconsole 并 Hook 到 PID

accessing MBeans in jconsole

<folder> ObjectName的一部分成为顶级目录,<name> ObjectName的一部分成为 MBean 名称本身。您现在可以使用add发送应用程序的方法String s 并查看它打印它们。很好,但是我们如何从命令行调用它?

首先,我们需要将 MBean 服务器注册到端口而不是 PID,这是通过使用以下 JVM 参数调用应用程序来完成的:

-Dcom.sun.management.jmxremote.port=<port> \
-Dcom.sun.management.jmxremote.ssl=false \
-Dcom.sun.management.jmxremote.authenticate=false \
-Dcom.sun.management.jmxremote=true

现在如果你运行 jconsole localhost:<port>您将直接连接到应用程序的 MBean 服务器。魔法。

这仍然没有达到我们想要的效果。有一个SO answer处理对 JMX 服务器的命令行访问,但我更喜欢简单地使用另一个助手应用程序。

此应用程序将启动,从命令行读取所有参数,然后调用使用给定参数指定的 MBean 方法。

这是一个简单的例子

public static void main(String[] args) throws Exception {
    final JMXServiceURL url = new JMXServiceURL("service:jmx:rmi:///jndi/rmi://:<port>/jmxrmi");
    final JMXConnector jmxc = JMXConnectorFactory.connect(url);
    final MBeanServerConnection mbsc = jmxc.getMBeanServerConnection();
    final ObjectName name = new ObjectName("com.example.producer:type=SomeUnqiueName");
    final ProducerMBean mbeanProxy = JMX.newMBeanProxy(mbsc, name, ProducerMBean.class, true);
    mbeanProxy.add("TEST");
    mbeanProxy.add("EXIT");
}

此应用程序需要具有 interface ProducerMBean在类路径上,最简单的方法是使用类路径上的主应用程序运行帮助程序。我们连接到运行在 localhost:<port> 上的 JMX 服务器然后获取与我们之前注册的同名的 MBean。

我们现在可以调用该 MBean 上的方法,将命令发送到其他应用程序。

显然,您需要重写帮助程序应用程序来读取命令行参数,然后您可以调用类似的内容

java -cp MyMainApp.jar:MyHelperApp.jar com.example.helper.Main add TEST EXIT

从您的脚本将参数传递给主 Java 程序。

关于java - 调用批处理运行jar的方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17359546/

相关文章:

java - "The constructor FastDateFormat(String, TimeZone, Locale) is not visible"是什么意思?

java - 执行 Kettle 转换

javascript - 将 var 从一个扩展函数传递到另一个扩展函数

从 Windows 批处理文件调用 Perl 脚本

windows - 为什么Windows中的%random%是基于时间的以及如何获得真正的随机数?

java - Glassfish ACC(应用程序客户端容器)的文档

java - 需要一些东西从主 Activity 向左滑动才能进入另一个 Activity

c++ - Windows __stdcall DLL 的 DEF 文件格式? (*.def -> lib.exe -> *.lib)

c - 了解参数为 const 时的函数声明?

batch-file - 使用批处理文件提取 .rar 文件