我有一個Java應用程序,它的主要功能是從批處理文件witch 2參數中調用的。 現在我想傳遞另一對參數到同一個應用程序,而不是打開另一個實例。 是否可以從外部調用正在運行的jar文件的主函數(或任何其他)?調用從批處理運行jar的方法
謝謝你的幫助!
我有一個Java應用程序,它的主要功能是從批處理文件witch 2參數中調用的。 現在我想傳遞另一對參數到同一個應用程序,而不是打開另一個實例。 是否可以從外部調用正在運行的jar文件的主函數(或任何其他)?調用從批處理運行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
s,並在其中斷或退出時收到String
「退出」。另一方面,製片人則更有趣一些。
首先,我們有interface ProducerMBean
,這是一個public interface
,我們將在後面看到它作爲交互的外向點。然後我們有一個Producer
其中implements ProducerMBean
,它只是將東西添加到BlockingQueue
。這裏值得注意的是,所有這些必須是線程安全的否則您將遇到JMX線程異步向您的應用程序線程戳您的方法的問題。
然後我們用平臺註冊我們的MBean(管理bean),這暴露了interface
到外面會;我們需要小心,因爲我們揭露的任何東西都可以被調用。 ObjectName
的格式爲<folder>:type=<name>
,稍後您會看到我的意思。
所以現在,當應用程序啓動時,它就像預期的那樣掛起。爲了發送Strings
我們需要打開JConsole的,並掛接到PID
的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程序。
哇,這是一個很好的答案。感謝你的付出!我希望我能以這種方式將其實現到我的應用程序中。 –
爲什麼不將方法本身的名稱作爲參數傳遞給主類,並在主類中構建執行該方法的邏輯?
是的,你可以創建一個更批處理文件並通過您不同的參數:
public static void main(String arg[])
爲主要方法的簽名接受陣列的字符串。通過儘可能多的,你想要的和你的jar支持。
這就是我所做的,但是當我再次調用它時,會調用另一個實例。我想通過它與以前一樣.. –
然後,您應該創建一個對象引用並存儲較早的實例,並在需要時使用該引用。 –
您可能無法訪問實際實例,但可以在新對象中操作數據。請參閱更多詳細信息:http://stackoverflow.com/questions/14741338/java-reflection-running-a-external-jar-and-referring-to-its-classes –
您需要監聽來自外部世界的數據。例如,它可以是網絡端口或控制檯。創建另一個線程,在收到一些數據時將監聽並運行內容。您也可以使用反射來調用任意方法(不僅是預定義的)。
您可以使用[JMX](http://docs.oracle.com/javase/tutorial/jmx/)。或者,您可以在應用程序中打開服務器套接字並通過該套接字發送數據。最不健壯的方式是使用文件進行數據交換。 –