我希望开发两个独立但相关的Java桌面应用程序。
我希望一个应用程序能够触发另一个应用程序,传递数据并可以编辑后传回,即通信是双向的。如果另一个应用程序已经运行,则希望它们之间直接通信,即不仅仅通过命令行传递参数等。
一般来说,我应该寻找哪些策略/技术来实现这一点?
我希望开发两个独立但相关的Java桌面应用程序。
我希望一个应用程序能够触发另一个应用程序,传递数据并可以编辑后传回,即通信是双向的。如果另一个应用程序已经运行,则希望它们之间直接通信,即不仅仅通过命令行传递参数等。
一般来说,我应该寻找哪些策略/技术来实现这一点?
为了展示让两个应用程序互相通信是多么容易,可以查看使用 JGroups 的网络剪贴板演示。只需启动两个实例并开始将文件拖放到其中一个实例中,第二个实例将立即显示相同的文件。
import java.io.Serializable;
import java.awt.*;
import java.awt.datatransfer.*;
import javax.swing.*;
import org.jgroups.*;
public class JGroupsTest {
public static void main(String[] args) throws Exception {
final JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
frame.setSize(500, 300);
final DefaultListModel listModel = new DefaultListModel();
final JList panel = new JList(listModel);
panel.setBackground(new Color(128, 0, 40));
panel.setForeground(new Color(240, 240, 240));
frame.add(panel);
System.setProperty("java.net.preferIPv4Stack", "true");
final JChannel channel = new JChannel("udp.xml");
channel.connect("networkclipboard");
channel.setReceiver(new ReceiverAdapter() {
@Override
public void viewAccepted(View newView) {
frame.setTitle("Network Clipboard - " + channel.getLocalAddress());
}
@Override
public void receive(Message msg) {
listModel.addElement(msg.getObject());
}
});
panel.setTransferHandler(new TransferHandler() {
@Override
public boolean importData(JComponent comp, Transferable t) {
DataFlavor[] transferDataFlavors = t.getTransferDataFlavors();
for (DataFlavor flavor : transferDataFlavors) {
try {
Object data = t.getTransferData(flavor);
if (data instanceof Serializable) {
Serializable serializable = (Serializable) data;
Message msg = new Message();
msg.setObject(serializable);
channel.send(msg);
}
} catch (Exception e) {
e.printStackTrace();
}
}
return super.importData(comp, t);
}
@Override
public boolean canImport(TransferSupport support) {
return true;
}
@Override
public boolean canImport(JComponent comp, DataFlavor[] transferFlavors) {
return true;
}
});
}
}
main
方法中使用 throws
的具体原因是什么,因为 main
方法是一个特定的方法,我们会用 try catch
包围它。请详细说明一下。 - Vishrantthrows
是允许的,不会有什么区别。我也经常为单元测试声明throws Exception
,这样我就不必逐个处理所有已检查异常。 - mhallerstruts
这样的容器中使用throws
关键字,但是在我的应用程序中编写main
方法(这是一个特定的方法而不是常见的方法)时,我使用try catch
块以自己的方式处理Exception
。是的,在main
方法中使用throws
会有所不同,如果main
方法中发生任何Exception
,它将被抛到JVM
并且您的程序将停止,同时JVM
以其自己的方式处理抛出的Exception
。throws
是“重新抛出异常”的概念,用于“常见方法”(许多类使用的方法)。 - Vishrant这取决于您希望如何通信这两个程序:
如果您只需要进程间信号量,可以在 /tmp 中的某个位置创建一个文件并锁定它。
如果您只需要进程间同步消息传递(远程过程调用),RMI 应该是最容易的。
如果您需要异步进程间消息传递,则 JMS 应该是最容易的。
如果您需要进程间共享内存,则使用映射文件。
如果您需要上述所有内容,Terracotta (http://www.terracotta.org/) 是最简单的方式:在同一台甚至不同计算机上的不同 JVM 上运行的 Java 程序彼此之间就好像在同一台机器上的一个 JVM 中执行一样。将一个程序分成几个甚至不需要进行任何代码更改-仅需编写 XML 配置文件。
你也应该考虑使用老牌的 RMI(远程方法调用)。
看一下JavaGroups,它可以解决您的通信问题,并帮助您检测其他应用程序是否在运行。如果应用程序没有运行,则必须使用java.lang.Runtime.exec()启动一个新的JVM...
采用“企业”方式运行这些应用程序将在Java EE服务器或至少Spring框架中运行。这可能是过度杀伤力的。
如果需要通信大量数据,则可以使用RMI。
如果您不害怕自己的协议、数据结构和错误处理,可以设置服务器和客户端套接字并通过它们进行通信。
我认为,通过在共享目录中的文件或通过共享数据库进行通信的替代方案具有一定的粗糙吸引力(设置自己的协议以确定何时写入或删除文件),虽然不是非常快速,但非常简单可靠。而且从外部监视“通信”也相当容易。
我赞同使用Socket通信和RMI。虽然RMI需要更多的操作,但对于程序员来说更直观。不过这取决于你要发送什么类型的信息。将原始字节推送到另一台机器可能比运行RMI服务器并处理所有相关问题更有意义...
这取决于您想在两个应用程序之间进行何种通信。例如,如果您使用套接字或RMI,那么两个应用程序都需要运行才能进行通信。如果您想要进行的通信类型可以更加异步,则可以使用更基于消息的方法。
例如,ZooKeeper允许您在非常简单而强大的原语之上实现几乎任何东西。此页面(http://hadoop.apache.org/zookeeper/docs/current/recipes.html)解释了如何使用ZooKeeper构建更高级别的结构。
缺点是您需要另一个系统。例如,如果您使用JGroups,那么就不需要。
希望这有所帮助。