1. 程式人生 > >實現自己的大發888平臺開發框架(采用Java Socket)

實現自己的大發888平臺開發框架(采用Java Socket)

exe provide lang 輸出流 reflect cati trace 客戶端 hand

大發888平臺開發實現原理圖:

1、Service API對應服務接口。

HelloService.java代碼如下:

package com.shan.rpc.service;

public interface HelloService {
    public String sayHello(String content);
}

2、Service Impl對應服務接口的實現:

HelloServiceImpl.java代碼如下:

package com.shan.rpc.service.impl;

import com.shan.rpc.service.HelloService;

public class HelloServiceImpl implements HelloService {
    public String sayHello(String content) {
        return "hello," + content;
    }
}

3、Consumer Proxy 角色對應服務消費者代理類。通過實現服務接口的動態代理對象獲得服務接口的動態代理實例Proxy.newProxyInstance,通過實現InvocationHandler接口中的invoke方法來完成遠程RPC的調用。具體通過輸出流將調用接口的方法及參數寫入Socket,發起遠程調用。之後通過Java對象輸入流從Socket獲得返回結果。

ConsumerProxy.java代碼如下:

package com.shan.rpc.framework;

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

public class ConsumerProxy {

    /**
     * @Title: consume
     * @Description:服務消費代理
     * @author fuss
     * @date 2018年7月12日
     * @param interfaceClass
     * @param host
     * @param port
     * @return
     * @throws Exception
     */
    public static <T> T consume(final Class<T> interfaceClass, final String host, final int port) throws Exception {
        return (T) Proxy.newProxyInstance(interfaceClass.getClassLoader(), new Class<?>[]{interfaceClass}, new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                Socket socket = new Socket(host, port);
                try {
                    ObjectOutputStream output = new ObjectOutputStream(socket.getOutputStream());
                    try {
                        output.writeUTF(method.getName());
                        output.writeObject(args);
                        ObjectInputStream input = new ObjectInputStream(socket.getInputStream());
                        try {
                            Object result = input.readObject();
                            if (result instanceof Throwable) {
                                throw (Throwable) result;
                            }
                            return result;
                        } finally {
                            input.close();
                        }
                    } finally {
                        output.close();
                    }
                } finally {
                    socket.close();
                }
            }
        });
    }

}

4、Provider Reflect角色對應服務發布實現。通過輸入流從Socket中按照ConsumerProxy的寫入順序註意獲取調動方法

名稱及方法參數,通過MethodUtils.invokeExactMethod對服務實現類發起反射調用,將調用結果寫入Socket返回給對方。

ProviderReflect.java代碼如下:

package com.shan.rpc.framework;

import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import org.apache.commons.lang3.reflect.MethodUtils;

public class ProviderReflect {

    private static final ExecutorService EXECUTOR_SERVICE = Executors.newCachedThreadPool();

    /**
     * @Title: provider
     * @Description:服務發布
     * @author fuss
     * @date 2018年7月12日
     * @param service
     * @param port
     * @throws Exception
     */
    public static void provider(final Object service, int port) throws Exception {
        ServerSocket serverSocket = new ServerSocket(port);
        while (true) {
            final Socket socket = serverSocket.accept();
            EXECUTOR_SERVICE.execute(new Runnable() {
                @Override
                public void run() {
                    try {
                        ObjectInputStream input = new ObjectInputStream(socket.getInputStream());
                        try {
                            try {
                                String methodName = input.readUTF();//方法名稱
                                Object[] args = (Object[]) input.readObject();//方法參數
                                ObjectOutputStream output = new ObjectOutputStream(socket.getOutputStream());
                                try {
                                    Object result = MethodUtils.invokeExactMethod(service, methodName, args);
                                    output.writeObject(result);
                                } catch (Throwable t) {
                                    output.writeObject(t);
                                } finally {
                                    output.close();
                                }
                            } catch (Exception e) {
                                e.printStackTrace();
                            } finally {
                                input.close();
                            }
                        } finally {
                            socket.close();
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                    }

                }
            });
        }
    }

}

然後寫main方法通過ProviderReflect發布服務,代碼如下:

package com.shan.rpc.invoke;

import com.shan.rpc.framework.ProviderReflect;
import com.shan.rpc.service.HelloService;
import com.shan.rpc.service.impl.HelloServiceImpl;

public class RpcProviderMain {

    public static void main(String[] args) throws Exception {
        HelloService service = new HelloServiceImpl();
        ProviderReflect.provider(service, 8083);
    }

}

客戶端調用遠程服務的main方法,代碼如下:

package com.shan.rpc.invoke;

import com.shan.rpc.framework.ConsumerProxy;
import com.shan.rpc.service.HelloService;

public class RpcConsumerMain {

    public static void main(String[] args) throws Exception {
        HelloService service = ConsumerProxy.consume(HelloService.class, "127.0.0.1", 8083);
        for (int i = 0; i < 1000; i++) {
            String hello = service.sayHello("fuss_" + i);
            System.out.println(hello);
            Thread.sleep(1000);
        }
    }

}

執行結果如圖:

實現自己的大發888平臺開發框架(采用Java Socket)