如何通过局域网(WiFi)在两个Java应用间实现方法调用?
我有两个通过局域网(WiFi网络)连接的Java应用,第一个为ServerApp.java,代码如下:
public class ServerApp { public static void zzz(){ System.out.println("hi"); } public static void main(String[] args) { try { ServerSocket ss=new ServerSocket(6666); Socket s=ss.accept(); DataInputStream dis = new DataInputStream(s.getInputStream()); String str =(String)dis.readUTF(); System.out.print("message : "+str); ss.close(); } catch (IOException e) { System.out.println(e); } } }
现需实现从其中一个Java应用调用另一个应用中的方法,请问该如何实现?
嘿,针对你的跨Java应用方法调用需求,我结合你现有的Socket代码,给你整理了几种实用的解决方案,你可以根据自己的场景来选:
1. 基于现有Socket手动封装调用协议
这是最贴近你现有代码的方式,不用额外加框架,自己定义一套简单的调用规则就行:
改造你的ServerApp
让它能识别客户端要调用的方法名,执行对应方法后还能返回结果:
import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import java.net.ServerSocket; import java.net.Socket; public class ServerApp { public static void zzz(){ System.out.println("hi"); } // 加个带参数和返回值的方法示例,方便你理解扩展 public static String getGreeting(String name) { return "Hello, " + name + "!"; } public static void main(String[] args) { try { ServerSocket ss = new ServerSocket(6666); System.out.println("服务器已启动,等待客户端连接..."); Socket s = ss.accept(); DataInputStream dis = new DataInputStream(s.getInputStream()); DataOutputStream dos = new DataOutputStream(s.getOutputStream()); // 读取客户端发来的调用指令,我们约定格式是「方法名:参数1,参数2...」 String callCommand = dis.readUTF(); System.out.println("收到调用指令: " + callCommand); // 解析指令,处理不同方法调用 String[] parts = callCommand.split(":"); String methodName = parts[0]; String result = ""; switch(methodName) { case "zzz": zzz(); result = "zzz方法执行完成"; break; case "getGreeting": if(parts.length > 1) { result = getGreeting(parts[1]); } else { result = "getGreeting方法缺少参数"; } break; default: result = "未知方法: " + methodName; } // 把执行结果回传给客户端 dos.writeUTF(result); // 记得关闭资源 dis.close(); dos.close(); s.close(); ss.close(); } catch (IOException e) { e.printStackTrace(); } } }
写个ClientApp来调用
客户端负责发送方法调用请求,接收服务器返回的结果:
import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import java.net.Socket; public class ClientApp { public static void main(String[] args) { try { // 这里替换成服务器的局域网IP,比如你服务器电脑的IP是192.168.1.100就填这个 Socket s = new Socket("192.168.1.100", 6666); DataOutputStream dos = new DataOutputStream(s.getOutputStream()); DataInputStream dis = new DataInputStream(s.getInputStream()); // 调用zzz方法 dos.writeUTF("zzz"); System.out.println("服务器返回: " + dis.readUTF()); // 调用带参数的getGreeting方法 dos.writeUTF("getGreeting:Mustafa"); System.out.println("服务器返回: " + dis.readUTF()); dos.close(); dis.close(); s.close(); } catch (IOException e) { e.printStackTrace(); } } }
这种方式的好处是轻量,完全用JDK自带的API就能实现,但缺点是要自己处理参数解析、异常和方法扩展,适合简单的小场景。
2. 使用Java RMI(远程方法调用)
这是Java官方提供的远程调用方案,更规范,适合需要频繁调用多个方法的复杂场景:
步骤1:定义远程接口
首先要写一个继承Remote的接口,所有要远程调用的方法都要在这里声明,而且必须抛出RemoteException:
import java.rmi.Remote; import java.rmi.RemoteException; public interface RemoteService extends Remote { void zzz() throws RemoteException; String getGreeting(String name) throws RemoteException; }
步骤2:实现服务器端的远程服务
写一个类实现上面的接口,继承UnicastRemoteObject:
import java.rmi.RemoteException; import java.rmi.server.UnicastRemoteObject; public class RemoteServiceImpl extends UnicastRemoteObject implements RemoteService { protected RemoteServiceImpl() throws RemoteException { super(); } @Override public void zzz() throws RemoteException { System.out.println("hi"); } @Override public String getGreeting(String name) throws RemoteException { return "Hello, " + name + "!"; } }
步骤3:启动RMI服务器
把服务注册到RMI注册表中:
import java.rmi.registry.LocateRegistry; import java.rmi.registry.Registry; public class RMIServer { public static void main(String[] args) { try { RemoteService service = new RemoteServiceImpl(); // 用默认的RMI端口1099创建注册表 Registry registry = LocateRegistry.createRegistry(1099); // 把服务绑定到注册表,名字叫RemoteService registry.rebind("RemoteService", service); System.out.println("RMI服务器已启动,服务已注册"); } catch (Exception e) { e.printStackTrace(); } } }
步骤4:客户端调用RMI服务
客户端连接到服务器的注册表,获取服务后直接调用方法:
import java.rmi.registry.LocateRegistry; import java.rmi.registry.Registry; public class RMIClient { public static void main(String[] args) { try { // 连接服务器的RMI注册表,替换成服务器的局域网IP Registry registry = LocateRegistry.getRegistry("192.168.1.100", 1099); RemoteService service = (RemoteService) registry.lookup("RemoteService"); // 直接调用远程方法,跟调用本地方法一样 service.zzz(); String greeting = service.getGreeting("Mustafa"); System.out.println(greeting); } catch (Exception e) { e.printStackTrace(); } } }
注意:运行RMI时,两端的远程接口类必须完全一致(包名、类名、方法签名都要一模一样),JDK9+可能需要加一些模块参数或者设置安全策略,具体可以根据报错调整。
3. 轻量级HTTP远程调用(比如Spring Boot)
如果你的应用是Spring Boot项目,用REST接口来实现会更通用,甚至支持跨语言调用:
服务器端(Spring Boot)
写一个Controller暴露方法为HTTP接口:
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RestController; @RestController public class RemoteMethodController { @GetMapping("/zzz") public String zzz() { System.out.println("hi"); return "zzz方法执行完成"; } @GetMapping("/greet/{name}") public String getGreeting(@PathVariable String name) { return "Hello, " + name + "!"; } }
客户端调用
用Spring的RestTemplate来调用这些接口:
import org.springframework.web.client.RestTemplate; public class HttpClient { public static void main(String[] args) { RestTemplate restTemplate = new RestTemplate(); // 替换成服务器的局域网IP和Spring Boot的端口(默认8080) String zzzResponse = restTemplate.getForObject("http://192.168.1.100:8080/zzz", String.class); System.out.println(zzzResponse); String greeting = restTemplate.getForObject("http://192.168.1.100:8080/greet/Mustafa", String.class); System.out.println(greeting); } }
这种方式的优势是通用性极强,任何支持HTTP的客户端都能调用,适合分布式场景,但需要引入Spring相关依赖。
内容的提问来源于stack exchange,提问作者mustafa-naeem

