Implement an RPC framework using Zookeeper and RMI technology

Use Zookeeper and RMI technology to implement an RPC framework.

Realize remote method invocation based on RMI:

1.1 Introduction to RMI:

Ava itself provides an RPC framework-RMI (that is, Remote Method Invoke remote method invocation). When writing an interface that needs to be used as a remote call, you need to inherit Remote. The Remote interface is used to identify that its method can be from a non-local virtual machine Only the methods specified in the "remote interface" extension java.rmi.Remote interface) can be used remotely.

RMI is a remote call of the Java language and cannot be implemented across languages.

1.2 Execution process

The Registry is the namespace where all server objects are placed. Each time the server creates a method, it will be registered in the Registry through the bind() or rebind() method, and bind a unique name in it.

If the client wants to remotely call the method in the Service, it needs to obtain the object (lookup() method) from the registry through the name bound to the server.

1.3 Introduction to RMI API

Remote interface

java.rmi.Remote defines this interface as a remote call interface. If the interface is called externally, you need to inherit this interface

mouth.

RemoteException 类

java.rmi.RemoteException inherits the interface of the Remote interface. If the method is allowed to be called remotely, this exception needs to be thrown.

UnicastRemoteObject 类

java.rmi.server.UnicastRemoteObject This class implements the Remote interface and the Serializable interface.

The custom interface implementation class needs to inherit this class in addition to implementing the custom interface.

LocateRegistry 类

java.rmi.registry.LocateRegistry can create a Registry on this machine through LocateRegistry, and you can access this Registry through a specific port.

Naming class

java.rmi.Naming Naming defines the RMI name that the published content can access. The specified remote method is also obtained through Naming.

1.4 Create Server

Create project
Insert picture description here

Create interface

Remote interface, the interface needs to inherit the Remote interface, and all methods in the interface must throw RemoteException

import java.rmi.Remote;
import java.rmi.RemoteException;

public interface UserService extends Remote {
    
    
        String findUsers(String str) throws RemoteException;
}

Create an interface implementation class

The remote interface implementation class must inherit UnicastRemoteObject (inherit RemoteServer->Inherit RemoteObject->Implement Remote, Serializable). Only by inheriting the UnicastRemoteObject class can it be indicated that it can be used as a remote object and registered in the registry for remote calls by the client (Supplement: The object found by the client lookup is only the stub (stub object) of the remote object, and the server object has a corresponding skeleton Skeleton (used to receive client stub requests and call the real object). Stub is a remote object Skeleton is the server-side proxy of remote objects, and they cooperate to complete the communication between the client and the server when the method is called.

import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;

public class UserServiceImpl extends UnicastRemoteObject implements UserService {
    
    

public UserServiceImpl() throws RemoteException{
    
    
}


    public String findUsers(String str) throws RemoteException {
    
    
        return "Hello Zookeeper" + str;
    }
}


Explanation: Why HelloImpl inherits UnicastRemoteObject and can be released as a remote object. Check the source code of UnicastRemoteObject to find:

    /**
     * Creates and exports a new UnicastRemoteObject object using an
     * anonymous port.
     *
     * <p>The object is exported with a server socket
     * created using the {@link RMISocketFactory} class.
     *
     * @throws RemoteException if failed to export object
     * @since JDK1.1
     */
    protected UnicastRemoteObject() throws RemoteException
    {
    
    
        this(0);
    }

	 /**
     * Creates and exports a new UnicastRemoteObject object using the
     * particular supplied port.
     *
     * <p>The object is exported with a server socket
     * created using the {@link RMISocketFactory} class.
     *
     * @param port the port number on which the remote object receives calls
     * (if <code>port</code> is zero, an anonymous port is chosen)
     * @throws RemoteException if failed to export object
     * @since 1.2
     */
    protected UnicastRemoteObject(int port) throws RemoteException
    {
    
    
        this.port = port;
        exportObject((Remote) this, port);
    }

    /**
     * Creates and exports a new UnicastRemoteObject object using the
     * particular supplied port and socket factories.
     *
     * <p>Either socket factory may be {@code null}, in which case
     * the corresponding client or server socket creation method of
     * {@link RMISocketFactory} is used instead.
     *
     * @param port the port number on which the remote object receives calls
     * (if <code>port</code> is zero, an anonymous port is chosen)
     * @param csf the client-side socket factory for making calls to the
     * remote object
     * @param ssf the server-side socket factory for receiving remote calls
     * @throws RemoteException if failed to export object
     * @since 1.2
     */
    protected UnicastRemoteObject(int port,
                                  RMIClientSocketFactory csf,
                                  RMIServerSocketFactory ssf)
        throws RemoteException
    {
    
    
        this.port = port;
        this.csf = csf;
        this.ssf = ssf;
        exportObject((Remote) this, port, csf, ssf);
    }

In fact, when the server side is started, the UserServerImpl object is new. Because it inherits UnicastRemoteObject, the parent class's construction method will be called first. At this time, this (current object) will be registered through the exportObject method.

Therefore, if the exported object needs to inherit other classes, you can export it as a remote object through the exportObject method instead of integrating UnicastRemoteObject:

...
// 创建一个远程对象
UserService userService = new UserServiceImpl();
//UserServiceImpl不需要继承UnicastRemoteObject类,通过exportObject将其显示导出
UnicastRemoteObject.exportObject(userService ,0);
...

Write the main method

The server startup class is used to create a remote object registry and register remote objects


import com.hkj.service.UserService;
import com.hkj.service.UserServiceImpl;
import org.apache.zookeeper.*;
import java.io.IOException;
import java.rmi.AlreadyBoundException;
import java.rmi.Naming;
import java.rmi.registry.LocateRegistry;

public class ServiceDemo implements Watcher {
    
    

    public static void main(String[] args)  throws IOException, AlreadyBoundException, KeeperException, InterruptedException {
    
    

        UserService userService = new UserServiceImpl();
        LocateRegistry.createRegistry(8888);
        String url = "rmi://localhost:8888/user";
        Naming.bind(url,userService);

        //将url信息放到zookeeper节点中
        ZooKeeper  zooKeeper = new ZooKeeper("192.168.1.111:2181,192.168.1.111:2182,192.168.1.111:2183",150000,new ServiceDemo());

        //创建Znode
        zooKeeper.create("/text/service",url.getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
        System.out.println("服务发布成功");

    }

    public void process(WatchedEvent watchedEvent) {
    
    
        if (watchedEvent.getState() == Event.KeeperState.SyncConnected){
    
    
            System.out.println("SUCCESS!");
        }
    }
}

1.5 Create Client layer

Create project

Insert picture description here

Server interface

public interface UserService {
    
    
    String findUser(String str);
}

Write the main method

import com.hkj.service.UserService;
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;

public class ClientDemo implements Watcher {
    
    
    public static void main(String[] args) throws IOException, NotBoundException, KeeperException, InterruptedException {
    
    
        ZooKeeper zooKeeper = new ZooKeeper("192.168.1.111:2181,192.168.1.111:2182,192.168.1.111:2183",
                150000,new ClientDemo());
        byte[] bytes = zooKeeper.getData("/test/service",new ClientDemo(),null);

        String url = new String(bytes);
        UserService userService = (UserService)Naming.lookup(url);

        String result = userService.findUser("Nuchkj");
        System.out.println(result);

    }

    public void process(WatchedEvent watchedEvent) {
    
    
        if(watchedEvent.getState() == Event.KeeperState.SyncConnected);
            System.out.println("连接成功");
    }
}

Guess you like

Origin blog.csdn.net/weixin_44192389/article/details/107735071