java RMI(Remote Method Invocation)远程方法调用。为什么称为远程方法调用呢?因为是两个JVM间进行通讯。两个JVM一个作为服务提供端,另一个作为服务调用端。
首先需要定义一个远程调用的接口,这个接口要继承Remote接口。并且远程接口方法要抛出RemoteException异常。
public interface RemoteService extends Remote {void sayHello(String name) throws RemoteException;
}
然后在服务端进行RemoteService接口方法的实现
public class RemoteServiceImpl implements RemoteService {@Overridepublic void sayHello(String name) {System.out.println("hello,"+name);}
}
服务注册
下一步通过Registry将上面的服务实现暴露出去,以供客户端调用。
RemoteService remoteService = new RemoteServiceImpl();
RemoteService stub = (RemoteService)UnicastRemoteObject.exportObject(remoteService, 0);
Registry registry = LocateRegistry.createRegistry(1099);
registry.rebind("RemoteService",stub);
这里看到首先我们使用UnicastRemoteObject.exportObject方法将我们的remoteService服务转换成一个stub代理实现,遵循rmi协议,这样当客户端调用时,会将该stub通过网络传递给客户端。第二个参数时指定TCP端口,0表示动态决定端口号。
stub这里怎么翻译呢?暂时就理解成原服务的占位引用或临时包装实现吧。
下一步通过LocateRegistry启动一个注册中心,然后将创建的stub绑定到注册中心,这里的stub绑定是按名称进行绑定的,同样客户端就可以按名称去获取需要调用的stub。
客户端调用
客户端调用就简单了,就是根据从注册中心根据名称获取到需要调用的服务的stub,然后调用对应的接口方法。
Registry registry = LocateRegistry.getRegistry("localhost", 1099);
RemoteService remoteService = (RemoteService)registry.lookup("RemoteService");
remoteService.sayHello("jack");
这里是跨JVM调用,连接register需要通过ip和端口,然后使用lookup方法进行服务的查找获取其对应的stub。最后进行接口方法的调用。
在java生态中,使用RMI的服务端和客户端遵循相同的接口进行开发,客户端不需要关心服务端具体实现,实现了业务的解耦,跨服务调用。这和后来的RPC架构是等效的。只不过RPC的协议报文更丰富,不局限于java生态。