分布式架构基础 三、基于通信及序列化技术实现简易RPC

简介

本次基于Socket通信、Java Serializable技术、动态代理、反射来实现接口的远程调用。

以用户、订单服务为例;
订单相关业务逻辑的处理及数据库交互是在订单服务内的;当用户服务内需要根据用户获取对应订单时,并不需要再与订单数据库交互,而是远程通信调用订单服务的内部实现;

实现逻辑

1. 公共模块 User-API module:

RpcRequest:

import java.io.Serializable;

public class RpcRequest implements Serializable {

    private static final long serialVersionUID = -1927810846083059872L;

    private String clazz;

    private String methodName;

    private Object[] args;

    private Class<?>[] types;

    public String getClazz() {
        return clazz;
    }

    public void setClazz(String clazz) {
        this.clazz = clazz;
    }

    public String getMethodName() {
        return methodName;
    }

    public void setMethodName(String methodName) {
        this.methodName = methodName;
    }

    public Object[] getArgs() {
        return args;
    }

    public void setArgs(Object[] args) {
        this.args = args;
    }

    public Class<?>[] getTypes() {
        return types;
    }

    public void setTypes(Class<?>[] types) {
        this.types = types;
    }
}

UserService

public interface UserService {

    String getUserName(int id);

    String getUserAuth(int userId);

}

2. 接口提供方: user-service module

UserServiceImpl


public class UserServiceImpl implements UserService {

    @Override
    public String getUserName(int id) {
        System.out.println("UserServer: execute getUserName " + id);
        return "Shen";
    }

    @Override
    public String getUserAuth(int userId) {
        System.out.println("UserServer: execute getUserAuth " + userId);
        return "Shen Auth";
    }

}

MainStarter

public class MainStarter {

    public static void main(String[] args) {

        int port = 8180;
        RpcServerSocket rpcServerSocket = new RpcServerSocket();
        rpcServerSocket.publish(port);

    }

}

RpcServerSocket


public class RpcServerSocket {

    static ExecutorService pool = Executors.newCachedThreadPool();

    public void publish(int port) {
        try {
        ServerSocket serverSocket = new ServerSocket(port);
            while (true) {
                Socket socket = serverSocket.accept();
                pool.execute(new SocketConnector(socket));
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

}

SocketConnector


import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.Socket;

public class SocketConnector implements Runnable {

    private Socket socket;

    public SocketConnector(Socket socket) {
        this.socket = socket;
    }

    @Override
    public void run() {

        ObjectInputStream objectInputStream;
        ObjectOutputStream objectOutputStream;
        try {
            objectInputStream = new ObjectInputStream(socket.getInputStream());
            Object request = objectInputStream.readObject();
            Object response = invoke(request);

            objectOutputStream = new ObjectOutputStream(socket.getOutputStream());
            objectOutputStream.writeObject(response);
            objectOutputStream.flush();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            // close io
        }

    }

    private Object invoke(Object request) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        RpcRequest rpcRequest = (RpcRequest) request;
        Class clazz = Class.forName(rpcRequest.getClazz());
        Method method = clazz.getMethod(rpcRequest.getMethodName(), rpcRequest.getTypes());
        String key = clazz.getName() + "." + method.getName();
        Object serviceObj = ServiceCache.serviceCache.get(key);
        return method.invoke(serviceObj, ((RpcRequest) request).getArgs());
    }

}

ServiceCache


import java.lang.reflect.Method;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

public class ServiceCache {

    static Map<String, Object> serviceCache = new ConcurrentHashMap<>();

    static {
        UserService userService = new UserServiceImpl();
        for (Method method : userService.getClass().getInterfaces()[0].getMethods()) {
            String key = userService.getClass().getInterfaces()[0].getName() + "." + method.getName();
            serviceCache.put(key, userService);
        }
    }

}

3. 接口调用方:order-service module

MainStarter


public class MainStarter {

    public static void main(String[] args) {

        String ip = "127.0.0.1";
        int port = 8180;

        UserService userService = (UserService) Proxy.newProxyInstance(UserService.class.getClassLoader(), new Class[]{UserService.class}, new RpcProxy(ip, port));

        String name = userService.getUserName(123);
        System.out.println(name);


        String auth = userService.getUserAuth(456);
        System.out.println(auth);

    }

}

RpcProxy


import com.bigshen.user.RpcRequest;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

public class RpcProxy implements InvocationHandler {

    private String ip;
    private int port;

    public RpcProxy(String ip, int port) {
        this.ip = ip;
        this.port = port;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

        RpcRequest rpcRequest = new RpcRequest();
        rpcRequest.setClazz(method.getDeclaringClass().getName());
        rpcRequest.setMethodName(method.getName());
        rpcRequest.setArgs(args);
        rpcRequest.setTypes(method.getParameterTypes());

        Object result = RpcNetTransfer.sendRequest(ip, port, rpcRequest);
        return result;
    }

}

RpcNetTransfer

import com.bigshen.user.RpcRequest;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.Socket;

public class RpcNetTransfer {


    public static Object sendRequest(String ip, int port, RpcRequest rpcRequest) {

        ObjectOutputStream objectOutputStream;
        ObjectInputStream objectInputStream;
        try {
            Socket socket = new Socket(ip, port);

            objectOutputStream = new ObjectOutputStream(socket.getOutputStream());
            objectOutputStream.writeObject(rpcRequest);
            objectOutputStream.flush();

            objectInputStream = new ObjectInputStream(socket.getInputStream());

            return objectInputStream.readObject();

        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } finally {
            // close io
        }

        return null;
    }

}
posted @ 2019-08-04 18:38  BigShen  阅读(131)  评论(0)    收藏  举报