Java to achieve a simple RPC framework

0 Preface

  RPC, called the Remote Procedure Call, Remote Procedure Call that is, it is a computer communications protocol. It allows local services like calling the same remote service call. It can have different implementations. Such as RMI (Remote Method Invocation), Hessian, Http invoker and so on. In addition, RPC is language-independent.

  Assume Computer1 calling sayHi () method, in terms of calls for Computer1 sayHi () method the same as calling a local method call -> return. Subsequent calls can be seen but the call is sayHi Computer2 Computer1 in () method, the RPC shields the underlying implementation details, let the caller without paying attention to the communication network, data transmission and other details.

1 RPC framework of realization

  The core principle of RPC: RPC enables local applications simple and efficient process server call (service).

  1. Communication Model: A to B machines and machine model assumes that communication with a communication between A and B, typically in the Java-based or BIO NIO ;.

  2. Process (service) Location: using a given communication mode, and determines the IP and port and method for determining the name of the specific process or method;

 

  3. Remote proxy object: Method (service) is actually a local proxy remote method, and therefore may require a remote proxy object for Java, the Java remote proxy object can be used to achieve dynamic object that encapsulates the call to a remote method invocation of the local transfer;

 

  4. The sequence of the object name, method name, parameters required for network transmission target information is converted into binary transmission, there may need different technical solutions serialization. Such as: protobuf, Arvo and so on.

 

2 RPC framework architecture

  RPC architecture is divided into three parts:

  1) service provider, run on the server to provide services and service implementation class interface definition.

  2) service center, running on the server side is responsible for local services publish to a remote service, remote management services, services provided to consumers.

  3) consumer service, running on the client, call the remote service through the remote proxy object.

3 specific implementation

  The service provider defines and implements the interface code is as follows:

public interface HelloService {
 
    String sayHi(String name);
 
}

  HelloServices interface categories:

public class HelloServiceImpl implements HelloService {
 
    public String sayHi(String name) {
        return "Hi, " + name;
    }
 
}

  Service code implementation, the code is as follows:

public interface Server {
    public void stop();
 
    public void start() throws IOException;
 
    public void register(Class serviceInterface, Class impl);
 
    public boolean isRunning();
 
    public int getPort();
}

  Service implementation class:

public class ServiceCenter implements Server {
    private static ExecutorService executor = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
 
    private static final HashMap<String, Class> serviceRegistry = new HashMap<String, Class>();
 
    private static boolean isRunning = false;
 
    private static int port;
 
    public ServiceCenter(int port) {
        this.port = port;
    }
 
    public void stop() {
        isRunning = false;
        executor.shutdown();
    }
 
    public void start() throws IOException {
        ServerSocket server = new ServerSocket();
        server.bind(new InetSocketAddress(port));
        . The System OUT .println ( " Start Server " );
         the try {
             the while ( to true ) {
                 // 1. listening client TCP connection after the TCP connection to the Task encapsulates, performed by a thread pool 
                Executor.execute ( new new serviceTask (server.accept ()));
            }
        } finally {
            server.close();
        }
    }
 
    public void register(Class serviceInterface, Class impl) {
        serviceRegistry.put(serviceInterface.getName(), impl);
    }
 
    public boolean isRunning() {
        return isRunning;
    }
 
    public int getPort() {
        return port;
    }
 
    private static class ServiceTask implements Runnable {
        Socket clent = null;
 
        public ServiceTask(Socket client) {
            this.clent = client;
        }
 
        public void run() {
            ObjectInputStream input = null;
            Output the ObjectOutputStream = null ;
             the try {
                 // 2. The code stream sent by the client deserialized into an object, reflection to invoke the service implementer, acquires the execution result 
                INPUT = new new the ObjectInputStream (clent.getInputStream ());
                String serviceName = input.readUTF();
                String methodName = input.readUTF();
                Class<?>[] parameterTypes = (Class<?>[]) input.readObject();
                Object[] arguments = (Object[]) input.readObject();
                Class serviceClass = serviceRegistry.get(serviceName);
                if (serviceClass == null) {
                    throw new ClassNotFoundException(serviceName + " not found");
                }
                Method method = serviceClass.getMethod(methodName, parameterTypes);
                Object result = method.invoke(serviceClass.newInstance(), arguments);
 
                // 3. Results of deserialization, sent to the client through the Socket 
                Output = new new the ObjectOutputStream (clent.getOutputStream ());
                output.writeObject(result);
            } catch (Exception e) {
                e.printStackTrace ();
            } finally {
                if (output != null) {
                    try {
                        output.close();
                    } catch (IOException e) {
                        e.printStackTrace ();
                    }
                }
                if (input != null) {
                    try {
                        input.close();
                    } catch (IOException e) {
                        e.printStackTrace ();
                    }
                }
                if (clent != null) {
                    try {
                        clent.close();
                    } catch (IOException e) {
                        e.printStackTrace ();
                    }
                }
            }
 
        }
    }
}
View Code

  Remote client proxy object:

public  class RpcClient <T> {
     public  static <T> T getRemoteProxyObj (Final Class <?> Where serviceInterface, the InetSocketAddress Final addr) {
         // 1. converting the interface call into a dynamic local agent JDK achieve dynamic interface proxies remote call 
        return (T) the Proxy.newProxyInstance (serviceInterface.getClassLoader (), new new Class <?> [] {} Where serviceInterface,
                 new new of InvocationHandler () {
                     public Object invoke (Object Proxy, Method, Method, Object [] args) {throws the Throwable
                        Socket socket = null;
                        ObjectOutputStream output = null;
                        INPUT the ObjectInputStream = null ;
                         the try {
                             // 2. Create Socket client, remote service provider connected to the address specified 
                            Socket = new new Socket ();
                            socket.connect(addr);
 
                            // 3. After the desired remote service call interface class, method names, and other coding parameter list sent to the service provider 
                            Output = new new the ObjectOutputStream (Socket.getOutputStream ());
                            output.writeUTF(serviceInterface.getName());
                            output.writeUTF(method.getName());
                            output.writeObject(method.getParameterTypes());
                            output.writeObject(args);
 
                            // 4. synchronous blocking wait for the server to return a response, returns a response after obtaining 
                            INPUT = new new the ObjectInputStream (Socket.getInputStream ());
                             return input.readObject ();
                        } finally {
                            if (socket != null) socket.close();
                            if (output != null) output.close();
                            if (input != null) input.close();
                        }
                    }
                });
    }
}
View Code

  Test Methods:

public class RPCTest {
 
    public static void main(String[] args) throws IOException {
        new Thread(new Runnable() {
            public void run() {
                try {
                    Server serviceServer = new ServiceCenter(8088);
                    serviceServer.register(HelloService.class, HelloServiceImpl.class);
                    serviceServer.start();
                } catch (IOException e) {
                    e.printStackTrace ();
                }
            }
        }).start();
        HelloService service = RPCClient.getRemoteProxyObj(HelloService.class, new InetSocketAddress("localhost", 8088));
        System.out.println(service.sayHi("test"));
    }
}

4 Improvement

  RPC simple framework to achieve here is to use the Java language development, highly coupled with the Java language, and Socket communication used is based on BIO achieved, IO is not efficient, as well as native Java serialization mechanism to account for too much memory, the operating efficiency It is not high. Improvement may be considered from the following methods.

  1. It can be based RPC JSON data frame transmission;
  2. NIO can be used directly or alternatively Netty BIO implemented;
  3. The use of open source serialization mechanism, such as Hadoop Avro and Google protobuf and so on;
  4. Zookeeper service registry can be used to manage, can make application more stable.

Guess you like

Origin www.cnblogs.com/huanghzm/p/11024843.html