RMI
RMI(Remote Method Invocation) 远程方法调用。
RMI 是从 JDK1.2 推出的功能,它可以实现在一个 Java 应用中可以像调用本地方法一样调用另一个服务器中 Java 应用(JVM)中的内容。
RMI 是 Java 语言的远程调用,无法实现跨语言。
执行流程
Registry(注册表)是放置所有服务器对象的命名空间。 每次服务端创建一个对象时,它都会使用 bind()或 rebind()方法注册该对象。 这些是使用称为绑定名称的唯一名称注册的。
要调用远程对象,客户端需要该对象的引用。即通过服务端绑定的名称从注册表中获取对象(lookup()方法)。
API介绍
Remote 接口
java.rmi.Remote 定义了此接口为远程调用接口。如果接口被外部调用,需要继承此接口。
RemoteException 类
java.rmi.RemoteException继承了 Remote 接口的接口,如果方法是允许被远程调用的,需要抛出此异常。
UnicastRemoteObject 类
java.rmi.server.UnicastRemoteObject此类实现了 Remote 接口和 Serializable 接口。自定义接口实现类除了实现自定义接口还需要继承此类。
LocateRegistry 类
java.rmi.registry.LocateRegistry可以通过 LocateRegistry 在本机上创建Registry,通过特定的端口就可以访问这个Registry
Naming 类
java.rmi.NamingNaming 定义了发布内容可访问 RMI 名称。也是通过Naming 获取到指定的远程方法。(bind lookup都在此下)
server端
package com.wyt;
import com.wyt.service.DemoService;
import com.wyt.service.Impl.DemoServiceImpl;
import java.net.MalformedURLException;
import java.rmi.AlreadyBoundException;
import java.rmi.Naming;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
public class demoServer {
public static void main(String[] args) throws RemoteException, AlreadyBoundException, MalformedURLException {
//将对象实例化
DemoService demoService=new DemoServiceImpl() ;
//创建本地注册表
LocateRegistry.createRegistry(8888);
//对象绑定到注册表中 8888/加唯一标识
Naming.bind("rmi://localhost:8888/demoService",demoService);
}
}
客户端
import com.wyt.service.DemoService;
import java.net.MalformedURLException;
import java.rmi.Naming;
import java.rmi.NotBoundException;
import java.rmi.RemoteException;
public class ClientDemo {
public static void main(String[] args) throws RemoteException, NotBoundException, MalformedURLException {
DemoService demoService=(DemoService) Naming.lookup("rmi://localhost:8888/demoService");
String result=demoService.demo("wangyuntong");
System.out.println(result);
}
}
使用zookeeper
package com.wyt;
import com.wyt.service.UsersService;
import com.wyt.service.impl.UsersServiceImpl;
import org.apache.zookeeper.*;
import java.io.IOException;
import java.net.MalformedURLException;
import java.rmi.AlreadyBoundException;
import java.rmi.Naming;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
public class ServerDemo implements Watcher {
public static void main(String[] args) throws IOException, AlreadyBoundException, KeeperException, InterruptedException {
UsersService usersService=new UsersServiceImpl();
LocateRegistry.createRegistry(8888);
String url="rmi://localhost:8888/user";
Naming.bind(url,usersService);
//将url放到zookeeper的节点中
ZooKeeper zooKeeper=new ZooKeeper("192.168.217.131:2181," +
"192.168.217.131:2182," +
"192.168.217.131:2183",150000,new ServerDemo());
zooKeeper.create("/wyt/service",url.getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE,
CreateMode.PERSISTENT_SEQUENTIAL);
System.out.println("服务发布成功");
}
@Override
public void process(WatchedEvent watchedEvent) {
if(watchedEvent.getState() == Event.KeeperState.SyncConnected){
System.out.println("chenggong");
}
}
}
package com.wyt;
import com.wyt.service.UsersService;
import org.apache.zookeeper.KeeperException;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.ZooKeeper;
import java.io.IOException;
import java.rmi.Naming;
import java.rmi.NotBoundException;
class ClientDemo implements Watcher {
public static void main(String[] args) throws IOException, KeeperException, InterruptedException, NotBoundException {
ZooKeeper zooKeeper=new ZooKeeper("192.168.217.131:2181," +
"192.168.217.131:2182," +
"192.168.217.131:2183",150000,new ClientDemo());
byte[] bytes=zooKeeper.getData("/wyt/service0000000001",new ClientDemo(),null);
String url=new String(bytes);
System.out.println(url);
UsersService userService=(UsersService)Naming.lookup(url);
String re=userService.findUsers("王韵通");
System.out.println(re);
}
@Override
public void process(WatchedEvent watchedEvent) {
if(watchedEvent.getState() == Event.KeeperState.SyncConnected){
System.out.println("chenggong");
}
}
}
切记:UsersService两个类名必须一致(服务端和客户端)