调用从批处理运行jar的方法 [英] Call a method of running jar from batch

查看:173
本文介绍了调用从批处理运行jar的方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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



感谢您的帮助!

解决方案

您应该使用JMX这样做,正如我在评论中提到的那样。



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



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

 私有静态类Consumer实现Runnable {

private final BlockingQueue< String> BlockingQueue的;

公共消费者(BlockingQueue< String> blockingQueue){
this.blockingQueue = blockingQueue;
}

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

公共静态接口ProducerMBean {

void add(String string);

String contents();
}

私有静态类生产者实现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 s,如果它被中断或收到<$ c $,则纾困c>字符串退出。另一方面,制作人更有趣。



首先我们有接口ProducerMBean ,这是一个公共接口,作为外向型交互点,我们将在后面看到。然后我们有一个生产者,其中实现了ProducerMBean ,它只是将东西添加到 BlockingQueue 。这里值得注意的是,所有这些必须是线程安全的否则您将遇到问题,JMX线程将您的方法异步地戳到应用程序线程。



<然后我们在平台上注册我们的MBean(管理bean),这会将接口暴露给外部;我们需要小心我们暴露的东西,因为我们暴露的任何东西都可以被调用。 ObjectName 的格式是< folder>:type =< name> ,你会明白我的意思稍后。



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





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



首先我们需要将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答案,它处理命令行访问a 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);
}

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



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



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

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

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


i have a Java application, which's main-function is called from a batch file witch 2 parameters. Now i want to pass another pair of parameters to the same app and not open another instance. Is it possible to call the main-function (or any other) of a running jar file from outside?

Thank you for your help!

解决方案

You should probably do this using JMX, as I mentioned in my comment.

JMX allows you to expose "management beans" from you program that can then be invoked remotely.

Lets start with a simple example:

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();
}

This is a producer/consumer pattern with a twist.

The consumer is perfectly boring, it spits out Strings from the queue and bails out if its interrupted or receives the String "EXIT". The producer on the other hand is a little more interesting.

First we have the interface ProducerMBean, this is a public interface and acts as the outward facing point of interaction as we shall see later. We then have a Producer which implements ProducerMBean, it simply adds things to the BlockingQueue. It's worth noting here that all this must be thread-safe otherwise you will have issues with the JMX threads poking your methods asynchronously to you application threads.

We then register our MBean (management bean) with the platform, this exposes the interface to the outside would; we need to be careful what we expose as anything we expose can be called. The format for the ObjectName is <folder>:type=<name>, you will see what I mean later.

So now, when the application is started it just hangs, as expected. In order to send Strings we need to open jconsole and hook into the PID

The <folder> part of the ObjectName becomes the top level directory and the <name> part of the ObjectName becomes the MBean name itself. You can now use the add method to send the app Strings and see it print them. Nifty, but how do we call that from the commandline?

First we need to register the MBean server to a port rather than a PID, this is done by invoking the application with the following JVM args:

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

Now if you run jconsole localhost:<port> you will connect directly to the application's MBean server. Magic.

This still doesn't quite do what we want. There is a SO answer that deals with commandline access to a JMX server, but I prefer to simply use another, helper, app.

This app would start, read all the arguments from the commandline, then invoke then MBean method specified with the arguments given.

Here is a simple example

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");
}

This application needs to have the interface ProducerMBean on the classpath, the easiest way is to run the helper with the main application on the classpath. We connect to the JMX server running on localhost:<port> and then get the MBean with the same name that we registered earlier.

We can now invoke methods on that MBean, sending commands to the other application.

Obviously you need to rewrite the helper app to read the commandline arguments, you could then invoke something like

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

From you script to pass in arguments to the main Java program.

这篇关于调用从批处理运行jar的方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆