RMIAPI
- 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.Naming
Naming 定义了发布内容可访问 RMI 名称。也是通过 Naming 获取到指定的远程方法。
RMI基本使用
服务端
创建工程
![](https://img2020.cnblogs.com/blog/1972142/202101/1972142-20210114014840180-479356591.png)
创建服务提供方接口
package com.xzlf.service;
import java.rmi.Remote;
import java.rmi.RemoteException;
// 服务提供方必须继承Remote接口
public interface DemoService extends Remote {
String demo(String str) throws RemoteException;
}
创建服务提供方接口实现
package com.xzlf.service;
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
public class DemoServiceImpl extends UnicastRemoteObject implements DemoService {
public DemoServiceImpl() throws RemoteException {
}
@Override
public String demo(String str) throws RemoteException {
return "Hello RMI " + str;
}
}
把接口注册到注册表中供远程调用
package com.xzlf.service;
import java.net.MalformedURLException;
import java.rmi.AlreadyBoundException;
import java.rmi.Naming;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
public class RMIApp {
public static void main(String[] args) throws RemoteException, AlreadyBoundException, MalformedURLException {
DemoService demoService = new DemoServiceImpl();
// 创建本地注册表
LocateRegistry.createRegistry(8888);
// 将对象绑定到注册表中
Naming.bind("rmi://localhost:8888/demo", demoService);
}
}
消费方
提供接口引用
package com.xzlf.service;
// 服务消费放不用继承Remote接口
public interface DemoService /*extends Remote */{
String demo(String str) /*throws RemoteException*/;
}
直接通过Naming.lookup静态方法获取远程对象
package com.xzlf.service;
import java.net.MalformedURLException;
import java.rmi.Naming;
import java.rmi.NotBoundException;
import java.rmi.RemoteException;
public class Client {
public static void main(String[] args) throws RemoteException, NotBoundException, MalformedURLException {
DemoService demoService = (DemoService) Naming.lookup("rmi://localhost:8888/demo");
String result = demoService.demo("张三");
System.out.println(result);
}
}
测试
![](https://img2020.cnblogs.com/blog/1972142/202101/1972142-20210114015514812-1551983131.png)
RMI+zookeeper使用
服务端
创建工程,导入依赖
![](https://img2020.cnblogs.com/blog/1972142/202101/1972142-20210114015656614-1530151048.png)
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
<version>3.6.0</version>
</dependency>
创建服务提供方接口
package com.xzlf.service;
import java.rmi.Remote;
import java.rmi.RemoteException;
public interface UserService extends Remote {
String getUserInfo(String name) throws RemoteException;
}
创建服务提供方接口实现
package com.xzlf.service.impl;
import com.xzlf.service.UserService;
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
public class UserSeriveImpl extends UnicastRemoteObject implements UserService {
// 注意修改构造方法为 public
public UserSeriveImpl() throws RemoteException {
super();
}
@Override
public String getUserInfo(String name) throws RemoteException {
return "zookeeper demo " + name;
}
}
把接口注册到注册表中并把地址添加到zookeeper注册中心供消费方获取
package com.xzlf.service.app;
import com.xzlf.service.UserService;
import com.xzlf.service.impl.UserSeriveImpl;
import org.apache.zookeeper.*;
import java.io.IOException;
import java.rmi.AlreadyBoundException;
import java.rmi.Naming;
import java.rmi.registry.LocateRegistry;
public class Demo implements Watcher {
public static void main(String[] args) throws IOException, AlreadyBoundException, KeeperException, InterruptedException {
UserService userService = new UserSeriveImpl();
LocateRegistry.createRegistry(9999);
String url = "rmi://localhost:9999/user";
Naming.bind(url, userService);
//将 url 信息放到 zookeeper 的节点中
ZooKeeper zooKeeper = new ZooKeeper("redis-server:2181", 15000, new Demo());
String path = zooKeeper.create("/service/user", url.getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
System.out.println("服务发布成功");
}
@Override
public void process(WatchedEvent event) {
if (event.getState() == Event.KeeperState.SyncConnected){
System.out.println("连接成功");
}
}
}
消费方
提供接口引用
package com.xzlf.service;
public interface UserService {
String getUserInfo(String name);
}
先从zookeeper注册中心获取远程地址,然后通过Naming调用
package com.xzlf.controller;
import com.xzlf.service.UserService;
import org.apache.zookeeper.KeeperException;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.ZooKeeper;
import org.apache.zookeeper.data.Stat;
import java.io.IOException;
import java.rmi.Naming;
import java.rmi.NotBoundException;
public class UserController implements Watcher {
public static void main(String[] args) throws IOException, NotBoundException, KeeperException, InterruptedException {
ZooKeeper zooKeeper = new ZooKeeper("redis-server:2181", 15000, new UserController());
byte[] data = zooKeeper.getData("/service/user", new UserController(), new Stat());
// 从zookeeper 获取远程调用url
UserService userService = (UserService) Naming.lookup(new String(data));
String userInfo = userService.getUserInfo("张三");
System.out.println(userInfo);
}
@Override
public void process(WatchedEvent event) {
if (event.getState() == Event.KeeperState.SyncConnected){
System.out.println("连接成功");
}
}
}
测试
zookeper
![](https://img2020.cnblogs.com/blog/1972142/202101/1972142-20210114020045395-1500393854.png)
控制台输出
![](https://img2020.cnblogs.com/blog/1972142/202101/1972142-20210114020101637-185508260.png)