素手でJavaのRPCフレームワークを引き裂くために - RPCフレームワークの原則を理解しやすいです

マイクロサービスの台頭によって、PRCは開発者として、私たちは、RPCフレームワーク、基盤となるRPCフレームワークの実装原理を理解する必要の使用を習得する必要があるだけでなく、マイクロサービス不可欠な一部となっています。コードはGitHubのにアップロードされたこちらをクリックして、一緒に学び探求する歓迎。

まず、RPCフレームワークは何ですか

私たちは別の方法でのプロジェクトに依存してもよいプロジェクトメソッドで開発されたが、単一のサーバー内のすべての、より簡単に理解するために、実装している前に、単一のプロジェクトでそのRPCリモートプロシージャコール(リモートプロシージャコール)、これは比較的簡単です。しかし、開発プロジェクトのこのアイデアは、後半、多くの場合、単一のサーバのパフォーマンスに影響を受け、保守や拡張プロジェクトを助長されていません。この目的のために、我々は新しい開発モデルを受け入れるために、PRCのフレームワークを学ぶ必要がある、それは私たちのモノマーの参照は、これらのアプリケーションの分解が別のスタンドアロンサーバーに展開することができる分解する前に、である必要があり、その場合、私たちでRPCフレームワークはマイクロサービスにリンクされている異なるサーバーに分散し、全体を構成するこれらを使用する必要があります。アプリケーションにアクセスする人々のために、彼は、モノマーの前にアプリケーションの背後にあるロジックを感じていなかったとのアクセスも例外ではありません。

それを達成するために、実際には、大きなプッシュをドロップし、分散型知識、および分散フレームワークは、PRCに依存します

第二に、原則として、RPCフレームワーク

RPCフレームワークを実装する前に、我々は、RPCフレームワークの原則を理解する必要があります

1、クライアント側

クライアント側では、リモートのメソッドを呼び出すためにその必要性は、それは、対応する方法の対応するリモートインスタンスを取得する必要はなく、ローカルで、このクラスでは、どのようにそれを達成するために?あなたがこの例で、対応する方法のリモートインスタンスを取得したいことができ、我々はリモート対応するメソッド呼び出しができ、動的プロキシのアイデアを考えるのは簡単です。質問は再び、でも、プロキシのインスタンスを取得するために、またはリモートメソッドは、接触ああを生成しないように。ハハ〜2台のコンピュータが接触を持って、自然は、ネットワークトラフィックああです。プロキシクラスのinvoke()メソッドを介して我々の方法は、通信ネットワークを介して、過去に渡されたメソッドパラメータと呼ぶことにします。最後に、通信ネットワークを介して、その結果は、RPCプロセスを完了するために、取得するために、リモートサーバから返されました。

2、サーバ端末

サーバー側は比較的簡単です実装、外部インターフェースにアクセスして、ポートでリッスンするために登録する必要があり、接続のために待機した後、解像度パラメータは、クライアントから送信され、その後、地元対応するメソッドを呼び出し、結果がクライアントに返されます。

3.契約

本契約は、実際にここに慣例である、と私たちの共通httpプロトコルは、データの解像度を超えるエンドツークライアントサーバ送信を容易にするために、ネットワーク内の指定されたパラメータを渡す方法、意思上の違いはありません。

第三に、RPCフレームワークを達成するために

1、準備プロトコルコード

なぜなら、ネットワークの伝送に、このクラスのニーズ、そして、Serializableインタフェースを実装する必要があり、ことをここで注意すべきパラメータの所定の伝送フォーマット。

/**
 * RPC请求协议类,需要实现序列化接口
 * @author Time
 * @created 2019/12/19
 */
public class RPCProtocol implements Serializable {
    // 接口的全类名
    String interfaceClassName;
    // 方法名称
    String methodName;
    // 参数类型数组
    Class<?>[] parameterTypes;
    // 参数对象数组
    Object[] parameterValues;

    public String getInterfaceClassName() {
        return interfaceClassName;
    }

    public void setInterfaceClassName(String interfaceClassName) {
        this.interfaceClassName = interfaceClassName;
    }

    public String getMethodName() {
        return methodName;
    }

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

    public Class<?>[] getParameterTypes() {
        return parameterTypes;
    }

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

    public Object[] getParameterValues() {
        return parameterValues;
    }

    public void setParameterValues(Object[] parameterValues) {
        this.parameterValues = parameterValues;
    }
}

2.クライアントコード

既に述べた上記のアイデアのクライアント実装、主は、動的プロキシクラスを作成し、パラメータを渡すネットワーク通信によって返された結果を得ることです。

/**
 * RPC框架核心实现类
 * @author Time
 * @created 2019/12/19
 */
public class RPCClient {
    /**
     * 通过动态代理获取到远程接口的具体实例,通过执行这个实例返回远程调用的结果
     * @param <T>
     * @return
     */
    public static <T> T getRemoteProxy(Class<T> interfaceClass, InetSocketAddress inetAddress){
        return (T) Proxy.newProxyInstance(interfaceClass.getClassLoader(),
                new Class[] {interfaceClass},
                new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                // 调用远程实例的方法
                try(Socket socket = new Socket()){
                    // 连接远程服务机
                    socket.connect(inetAddress);
                    // 获取输入输出流
                    try(
                            ObjectOutputStream serialize = new ObjectOutputStream(socket.getOutputStream());
                            ObjectInputStream deSerialize = new ObjectInputStream(socket.getInputStream());
                            ){
                        // 创建一个rpc框架的请求协议对象
                        RPCProtocol rpcProtocol = new RPCProtocol();
                        // 填充属性
                        rpcProtocol.setInterfaceClassName(interfaceClass.getName());
                        rpcProtocol.setMethodName(method.getName());
                        rpcProtocol.setParameterTypes(method.getParameterTypes());
                        rpcProtocol.setParameterValues(args);
                        // 协议对象序列化,进行网络传输
                        serialize.writeObject(rpcProtocol);

                        // 服务端生成的结果反序列化
                        Object result = deSerialize.readObject();
                        // 结果返回
                        return result;
                    }

                }catch (Exception e){
                    e.printStackTrace();
                }
                return null;
            }
        });
    }
}

図3に示すように、サーバ側のコード

ここでは、複数のクライアントからのハンドル要求にスレッドプールを作成することもできます。

/**
 1. RPC框架核心服务类
 2. 步骤:
 3. 1 暴露调用接口
 4. 2 启动服务
 5. @author Time
 6. @created 2019/12/19
 */
public class RPCServer {
    // 定义存储暴露的接口
    HashMap<String, Object> hashMap = new HashMap<>();
    // 定义一个线程池
    ThreadPoolExecutor poolExecutor = new ThreadPoolExecutor(8, 20, 200 , TimeUnit.MICROSECONDS,
            new ArrayBlockingQueue(10)
            );

    //  暴露服务的接口
    public void publicServiceAPI(Class<?> clazz, Object instance){
        this.hashMap.put(clazz.getName(), instance);
    }

    // 发布服务的方法
    public void start(int port){
        // 创建网络服务端
        try {
            ServerSocket serverSocket = new ServerSocket();
            //绑定端口哦
            serverSocket.bind(new InetSocketAddress(port));
            System.out.println("===================RPC Server服务端启动成功===================");

            // 创建客户端处理请求的线程
            while (true){
                poolExecutor.execute(new ServerTask(serverSocket.accept()));
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

    }
    private class ServerTask implements Runnable{
        private Socket socket;
        public ServerTask(Socket socket){
            this.socket = socket;

        }
        @Override
        public void run() {
            try(
                    ObjectInputStream deserialize = new ObjectInputStream(socket.getInputStream());
                    ObjectOutputStream serialize = new ObjectOutputStream(socket.getOutputStream())
            ){
                // 反序列获取客户端的协议
                RPCProtocol rpcProtocol = (RPCProtocol) deserialize.readObject();
                // 通过客户端传来的值获取对应的接口
                System.out.println(rpcProtocol.getInterfaceClassName());
                Object instance = hashMap.get(rpcProtocol.getInterfaceClassName());
                // 利用反射通过实例以及参数获取调用的具体方法
                Method method = instance.getClass().getDeclaredMethod(rpcProtocol.getMethodName(),
                        rpcProtocol.getParameterTypes());
                //  执行方法获取对应的结果
               Object result =  method.invoke(instance,rpcProtocol.getParameterValues());
               // 将执行的结果序列化,传回给客户端
                serialize.writeObject(result);

            }catch (Exception e){
                e.printStackTrace();
            }

        }
    }
}
4、試験
  1. サービスインスタンス
public class App 
{
    public static void main( String[] args )
    {
        // 获取服务端
        RPCServer server = new RPCServer();
        // 暴露接口
        server.publicServiceAPI(UserService.class, new UserServiceImpl());
        // 发布服务
        server.start(8888);
    }
}

  1. クライアントの例
public class App 
{
    public static void main( String[] args )
    {
        UserService userService = RPCClient.getRemoteProxy(UserService.class,new InetSocketAddress("127.0.0.1",8888));
        String result = userService.addUserName("王五");
        System.out.println(result);
    }
}

概要:上記は単純な実装では、基本的な原理を説明するのである、コードはGitHubのにアップロードされていますしかし、人気のRPCフレームワークは、興味を持っている、そのような言葉、負荷分散、ヒューズ、動的監視およびその他のコンテンツのシーケンスとしてより多くのものを、検討する必要があるでしょう、あなたは、このようなアリダブル、シーナと他のMotanとして人気のRPCフレームワーク、学ぶことができます。

公開された66元の記事 ウォン称賛26 ビュー10000 +

おすすめ

転載: blog.csdn.net/Time__Lc/article/details/103754507