基于TCP和HTTP两种协议的简易RPC实现

1、基于Java的socket API,可以实现一个简单的RPC调用。

基于TCP和HTTP两种协议的简易RPC实现_第1张图片

具体实现代码如下,原则仅仅是为了便于展示调用过程。

// 接口类
public interface SayHelloService {

    /**
     * say hello method
     * @param helloArgs args
     * @return string
     */
    String sayHello(String helloArgs);
}

// 接口实现类
public class SayHelloServiceImpl implements SayHelloService {

    @Override
    public String sayHello(String helloArgs) {

        String cmpArgs = "hello";

        if (cmpArgs.equals(helloArgs)){
            return "hello";
        } else {
            return "bye bye";
        }
    }
}

// 服务提供类
public class ServiceProvider {

    void monitor() throws Exception {

        Map<String,Object> services = new HashMap<>();
        services.put("com.loongshawn.test.service.SayHelloService",new SayHelloServiceImpl());

        ServerSocket sever = new ServerSocket(1234);

        while (true) {
            Socket socket = sever.accept();

            System.out.println("server socket accept");

            // 读取服务信息
            ObjectInputStream input = new ObjectInputStream(socket.getInputStream());
            String interfaceName = input.readUTF();
            String methodName = input.readUTF();
            Class<?>[] parameterTypes = (Class<?>[])input.readObject();
            Object[] arguments = (Object[])input.readObject();

            System.out.println(interfaceName + "," + methodName + "," + parameterTypes + "," + arguments);

            // 执行调用
            Class servicesInterfaceClass = Class.forName(interfaceName);
            Object service = services.get(interfaceName);
            Method method = servicesInterfaceClass.getMethod(methodName,parameterTypes);
            Object result = method.invoke(service,arguments);

            System.out.println("server method execute result:" + result);

            ObjectOutputStream output = new ObjectOutputStream(socket.getOutputStream());
            output.writeObject(result);

        }

    }

// 服务消费类
public class ServiceConsumer {

    void doSend() throws Exception{

        String interfaceName = SayHelloService.class.getName();

        Method method = SayHelloService.class.getMethod("sayHello",java.lang.String.class);

        Object[] arguments = {"hello"};

        Socket socket = new Socket("127.0.0.1",1234);

        ObjectOutputStream output = new ObjectOutputStream(socket.getOutputStream());
        output.writeUTF(interfaceName);
        output.writeUTF(method.getName());
        output.writeObject(method.getParameterTypes());
        output.writeObject(arguments);

        System.out.println(interfaceName + "," + method.getName() + "," + method.getParameterTypes() + "," + arguments);

        ObjectInputStream input = new ObjectInputStream(socket.getInputStream());
        Object result = input.readObject();

        System.out.println("client request result:" + result);
    }

server端运行结果:
基于TCP和HTTP两种协议的简易RPC实现_第2张图片

consumer端运行结果:
基于TCP和HTTP两种协议的简易RPC实现_第3张图片

基于TCP socket这种方式实现RPC更多的是与输入输出流打交道,将数据写入outputstream,从inputstream中读数据,都是一些底层的工作。在现在这个应用呈现爆炸性扩张的年代,这种方式的开发效率显得低下,同时也面临并发同步等挑战,因此来看看另外一种实现。

2、基于Java的httpclient API,可以实现一个简单的RPC调用。

基于http协议的RPC实现,构建图与socket类似,只不过具体请求的代码被httpclient相关代码取代。

具体实现代码如下,通过springboot工程部署server端服务,仅展示服务提供端方法,这个方法在一个Controller中,用来响应http请求。

@RequestMapping(value = "/service")
    @ResponseBody
    Object doGet(@RequestParam("interfaceName") String interfaceName,
                              @RequestParam("method") String methodName,
                              @RequestParam("parameterTypes") String parameterTypes,
                              @RequestParam("arguments") String arguments
               ) throws Exception {

        Map<String,Object> services = new HashMap<>();
        services.put("com.loongshawn.test.service.SayHelloService",new SayHelloServiceImpl());

        System.out.println(interfaceName + "," + methodName + "," + parameterTypes + "," + arguments);

        // 执行调用
        Class servicesInterfaceClass = Class.forName(interfaceName);
        Object service = services.get(interfaceName);
        Method method = servicesInterfaceClass.getMethod(methodName,parameterTypes.getClass());
        Object result = method.invoke(service,arguments);

        System.out.println("server method execute result:" + result);

        return result;
    }

客户端请求代码如下,将参数的传递、请求、结果响应交给httpclient工具,这个Apache下面的一个工具包。类似的http工具包还有unirest工具,比httpclient使用起来更简洁。

void doGet() throws Exception{


        String interfaceName = SayHelloService.class.getName();

        Method method = SayHelloService.class.getMethod("sayHello",java.lang.String.class);

        String arguments = "hello";

        String url = "http://127.0.0.1:8080/service?" +
                "interfaceName=" + interfaceName + "&method=" + method.getName() +
                "¶meterTypes=" + "java.lang.String" + "&arguments=" + arguments;

        HttpClientServiceImpl httpClientService = new HttpClientServiceImpl();
        String result = httpClientService.doGet(url);

        System.out.println(url);
        System.out.println("client request result:" + result);
    }

server端运行结果:
基于TCP和HTTP两种协议的简易RPC实现_第4张图片

consumer端运行结果:
基于TCP和HTTP两种协议的简易RPC实现_第5张图片

http实现的RPC方便之处在于还能通过浏览器测试:

http://127.0.0.1:8080/service?interfaceName=com.loongshawn.test.service.SayHelloService&method=sayHello¶meterTypes=java.lang.String&arguments=hello

基于TCP和HTTP两种协议的简易RPC实现_第6张图片

http://127.0.0.1:8080/service?interfaceName=com.loongshawn.test.service.SayHelloService&method=sayHello¶meterTypes=java.lang.String&arguments=bye

基于TCP和HTTP两种协议的简易RPC实现_第7张图片

3、结束语

展示的两种RPC实现当然不能应对大规模的SOA构架实现,但服务端方法调用机制还是能够借用。高并发环境下的SOA构架,利用zookeeper进行RPC服务治理是一种选择,目前阿里内部使用的是HSF框架(https://blog.csdn.net/loongshawn/article/details/73903709 ),对外开源的是dubbo来进行服务治理。产品太多,也不可能都学一遍,可以先学学zookeeper的工作机制,至少能搭个可用的demo起来。不同的企业拥抱的技术栈和方案不同,了解了相关的机制时切换时也会容易些。

你可能感兴趣的:(JAVA,Http,HSF)