JDK原生RMI结合zookeeper使用

RMIAPI

  1. Remote 接口
    java.rmi.Remote
    定义了此接口为远程调用接口。如果接口被外部调用,需要继承此接口。
  2. RemoteException 类
    java.rmi.RemoteException
    继承了 Remote 接口的接口,如果方法是允许被远程调用的,需要抛出此异常。
  3. UnicastRemoteObject 类
    java.rmi.server.UnicastRemoteObject
    此类实现了 Remote 接口和 Serializable 接口。
    自定义接口实现类除了实现自定义接口还需要继承此类
  4. LocateRegistry 类
    java.rmi.registry.LocateRegistry
    可以通过 LocateRegistry 在本机上创建 Registry,通过特定的端口就可以访问这个Registry。
  5. Naming 类
    java.rmi.Naming
    Naming 定义了发布内容可访问 RMI 名称。也是通过 Naming 获取到指定的远程方法。

RMI基本使用

服务端

创建工程

创建服务提供方接口

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);
    }
}

测试

RMI+zookeeper使用

服务端

创建工程,导入依赖

       <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://www.cnblogs.com/xzlf/p/14275271.html