我正在寻求开发两个独立(但相关)的 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;
}
});
}
}
这取决于您希望如何传达这两个程序:
如果您只需要进程间信号量,请在 /tmp 中的某个位置创建一个文件并将其锁定。
如果您只需要进程间同步消息传递(远程过程调用),RMI 应该是最简单的。
如果您需要异步进程间消息传递,JMS 应该是最简单的。
如果需要进程间共享内存,请使用映射文件。
如果您需要以上所有内容,Terracotta是最简单的方法:同一台甚至不同计算机上的不同 JVM 上的 Java 程序可以看到彼此,就好像它们在一台计算机上的一个 JVM 中执行一样。将一个程序分成几个甚至不需要更改任何代码 - 编写一个 XML 配置文件就足够了。
您还应该考虑优秀的经典 RMI。
看看JavaGroups,它将解决您的通信问题,还可以帮助您检测其他应用程序是否正在运行。如果应用程序没有运行,您将必须使用 java.lang.Runtime.exec() 为其启动一个新的 JVM...
尝试使用 SocketCommunication 进行通信,即使应用程序位于同一台机器中。
在这里可以找到有关如何操作的更多信息(Sun/Java 文档)。
“企业”方式是在 Java EE 服务器或至少在 Spring 框架中运行这些应用程序。这也可能太过分了。
如果需要通讯一堆数据,那么RMI就可以做到。
如果您不怕破坏自己的协议、数据结构和错误处理,您可以设置服务器和客户端套接字并通过它们进行通信。
我认为通过公共目录中的文件(设置您自己的协议来确定谁何时写入或删除文件)或通过共享数据库进行通信的替代方案有一定的吸引力。技术含量低,速度不是特别快,但非常简单可靠。而且从外部监控“通讯”相当容易。
为了简单起见,为什么不直接使用普通的 TCP 套接字?
我第二个Socket通信和RMI。 RMI 稍微复杂一些,但对于程序员来说更直观。这取决于您发送的信息类型。将原始字节推送到另一台机器可能比运行 RMI 服务器并处理所有这些爵士乐更有意义......
这取决于您想在两个应用程序之间进行哪种通信。例如,如果您使用套接字或 RMI,则两个应用程序都需要启动才能进行通信。如果您想要进行的通信类型可以更加异步,那么您可以更多地使用基于消息传递的方法。
例如,ZooKeeper 允许您在非常简单但功能强大的原语之上实现几乎任何您想要的东西。此页面 (http://hadoop.apache.org/zookeeper/docs/current/recipes.html) 解释了如何使用 ZooKeeper 构建更高级别的构造。
缺点是你需要另一个系统。例如,如果您使用 JGroups,那么您就不需要。
希望这有帮助
根据您正在寻找的通信方式(高延迟、大量数据等)以及该系统是否可以扩展到超过 2 个 java 系统,可能是使用中间件解决方案的消息传递系统,例如Tibco 智能插座。
有关您的设置和期望的更多信息都会有所帮助。
最简单的是 使用 RMI,无需独立的 rmiregistry。
服务器创建本地注册表:
ServerImpl extends UnicastRemoteObject implements Server
rmiRegistry = LocateRegistry.createRegistry(2020);
rmiRegistry.bind("server", aServerImpl);
客户端使用 rmi url 进行查找(类似于 corbaloc:)
String url = "rmi://localhost:2020/server";
Server server = (Server) Naming.lookup(url);
我在 500 毫秒内通过同一打开的连接在循环中收到 1000 个调用。是的,那就是毫秒。
想法和示例来自此处:https://www.censhare.com/us/resources/blog/article/file-streaming-using-java-rmi