2013-06-28 29 views
0

我有一個Java應用程序,它的主要功能是從批處理文件witch 2參數中調用的。 現在我想傳遞另一對參數到同一個應用程序,而不是打開另一個實例。 是否可以從外部調用正在運行的jar文件的主函數(或任何其他)?調用從批處理運行jar的方法

謝謝你的幫助!

+0

您可以使用[JMX](http://docs.oracle.com/javase/tutorial/jmx/)。或者,您可以在應用程序中打開服務器套接字並通過該套接字發送數據。最不健壯的方式是使用文件進行數據交換。 –

回答

4

你應該使用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 s,並在其中斷或退出時收到String「退出」。另一方面,製片人則更有趣一些。

首先,我們有interface ProducerMBean,這是一個public interface,我們將在後面看到它作爲交互的外向點。然後我們有一個Producer其中implements ProducerMBean,它只是將東西添加到BlockingQueue。這裏值得注意的是,所有這些必須是線程安全的否則您將遇到JMX線程異步向您的應用程序線程戳您的方法的問題。

然後我們用平臺註冊我們的MBean(管理bean),這暴露了interface到外面會;我們需要小心,因爲我們揭露的任何東西都可以被調用。 ObjectName的格式爲<folder>:type=<name>,稍後您會看到我的意思。

所以現在,當應用程序啓動時,它就像預期的那樣掛起。爲了發送Strings我們需要打開JConsole的,並掛接到PID

accessing MBeans in jconsole

ObjectName<folder>部分成爲頂級目錄和ObjectName<name>部分成爲MBean名稱本身。您現在可以使用add方法發送應用程序String,並看到它打印出來。漂亮,但我們如何從命令行調用它?

首先我們需要註冊MBean服務器的端口,而不是一個PID,這是通過調用與以下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 

現在,如果你運行jconsole localhost:<port>您將直接連接到應用程序的MBean服務器。魔法。

這仍然不完全是我們想要的。有一個處理命令行訪問JMX服務器的SO answer,但我更喜歡簡單地使用另一個幫助器應用程序。

該應用程序將啓動,讀取命令行中的所有參數,然後調用指定給定參數的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"); 
} 

此應用程序需要對classpath中interface ProducerMBean,最簡單的方法是用在類路徑中的主要應用運行幫手。我們連接到在localhost:<port>上運行的JMX服務器,然後獲取與之前註冊的名稱相同的MBean。

我們現在可以調用該MBean上的方法,將命令發送到其他應用程序。

顯然,你需要重寫助手應用程序來讀取命令行參數,你可以然後調用類似

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

從你的腳本參數傳遞給主要的Java程序。

+0

哇,這是一個很好的答案。感謝你的付出!我希望我能以這種方式將其實現到我的應用程序中。 –

0

爲什麼不將方法本身的名稱作爲參數傳遞給主類,並在主類中構建執行該方法的邏輯?

0

是的,你可以創建一個更批處理文件並通過您不同的參數:

public static void main(String arg[]) 

爲主要方法的簽名接受陣列的字符串。通過儘可能多的,你想要的和你的jar支持。

+0

這就是我所做的,但是當我再次調用它時,會調用另一個實例。我想通過它與以前一樣.. –

+0

然後,您應該創建一個對象引用並存儲較早的實例,並在需要時使用該引用。 –

+0

您可能無法訪問實際實例,但可以在新對象中操作數據。請參閱更多詳細信息:http://stackoverflow.com/questions/14741338/java-reflection-running-a-external-jar-and-referring-to-its-classes –

1

您需要監聽來自外部世界的數據。例如,它可以是網絡端口或控制檯。創建另一個線程,在收到一些數據時將監聽並運行內容。您也可以使用反射來調用任意方法(不僅是預定義的)。