手写RPC(八) provider、consumer 实现

首先,我们的provider是需要提供rpc服务的,而我们 rpc底层是需要依赖netty的,因此我们需要依赖我们已经编写好的rpc-protocol模块。
rpc-provider模块 pom.xml文件添加

 <dependency>
       <groupId>com.info</groupId>
       <artifactId>rpc-protocol</artifactId>
       <version>1.0-SNAPSHOT</version>
 </dependency>

启动netty服务端

package com.info.provider;

import com.info.protocol.netty.server.NettyServer;

public class ProviderApplication {
    
    

    public static void main(String[] args) {
    
    
        new NettyServer("localhost", 9000).startServer();
    }
}

接下来编写rpc-consumer模块,因为rpc-consumer需要使用netty客户端发送请求,同样需要依赖rpc-protocol
其实,在客户端我们可以直接生成protocol对象设置相应的参数,然后使用netty客户端把这个对象传输出去即可,然后考虑到通用性,这里考虑使用代理的方式生成被调用对象代理对象的方法来完成。
我们知道jdk提供了一个java.lang.reflect.Proxy来方便我们生成代理对象

Proxy provides static methods for creating dynamic proxy classes and
instances, and it is also the superclass of all dynamic proxy classes
created by those methods. To create a proxy for some interface Foo:

   InvocationHandler handler = new MyInvocationHandler(...);
   
   Class<?> proxyClass = Proxy.getProxyClass(Foo.class.getClassLoader(), Foo.class);
   
   Foo f = (Foo) proxyClass.getConstructor(InvocationHandler.class).
                   newInstance(handler);  

or more simply:

   Foo f = (44Foo) Proxy.newProxyInstance(Foo.class.getClassLoader(),
                                        new Class<?>[] { Foo.class },
                                        handler);

根据jdk的代码示例,生成一个代理类需要三个参数,分别是类加载器,代理类需要实现的接口集合,以及一个InvocationHandler,因此我们需要实现一个自定义InvocationHandler,这也是实现动态代理对原方法增强的实现。

package com.info.consumer;

import com.info.protocol.constants.CommonConstant;
import com.info.protocol.enums.MessageTypeEnum;
import com.info.protocol.enums.SerializeTypeEnum;
import com.info.protocol.netty.client.NettyClient;
import com.info.protocol.netty.core.*;
import io.netty.channel.DefaultEventLoop;
import io.netty.util.concurrent.DefaultPromise;
import lombok.extern.slf4j.Slf4j;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

@Slf4j
public class CustomInvocationHandler implements InvocationHandler {
    
    

    private final String serviceAddress;

    private final int servicePort;

    public CustomInvocationHandler(String serviceAddress, int servicePort) {
    
    
        this.serviceAddress = serviceAddress;
        this.servicePort = servicePort;
    }


    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    
    
        log.info("begin invoke target server");
        //组装参数
        Protocol<Request> protocol = new Protocol<>();
        long requestId = RequestHolder.REQUEST_ID.incrementAndGet();
        // 魔数 16bit|协议版本 8bit|序列化方式 8bit| 消息长度 32bit |消息类型(请求还是响应)2bit|messageId 64bit
        Header header = new Header(CommonConstant.MAGIC, CommonConstant.PROTOCOL_VERSION,
                SerializeTypeEnum.JDK.getCode(), 0, MessageTypeEnum.REQUEST.getCode(), requestId);
        protocol.setHeader(header);
        Request request = new Request();
        request.setClassName(method.getDeclaringClass().getName());
        request.setMethodName(method.getName());
        request.setParameterTypes(method.getParameterTypes());
        request.setParams(args);
        protocol.setContent(request);
        //发送请求
        NettyClient nettyClient = new NettyClient(serviceAddress, servicePort);
        //构建异步数据处理
        CustomFuture<Response> future = new CustomFuture<>(new DefaultPromise<>(new DefaultEventLoop()));
        RequestHolder.REQUEST_MAP.put(requestId, future);
        nettyClient.sendRequest(protocol);
        return future.getPromise().get().getData();
    }
}

封装一个生成代理对象的方法

package com.info.proxy;

import java.lang.reflect.Proxy;

public class ClientProxy {
    
    

    public <T> T clientProxy(final Class<T> interfaceCls, final String host, final int port) {
    
    
        return (T) Proxy.newProxyInstance
                (interfaceCls.getClassLoader(),
                        new Class<?>[]{
    
    interfaceCls},
                        new CustomInvocationHandler(host, port));
    }
}

至此,完美所有的代码都已经编写完毕,第一次编写一个rpc框架的你是不是稍稍膨胀了一下?当时的我也是这样子的心态!
下节完美开始编写测试代码进行测试。

系列文章传送门如下:
手写RPC(一) 絮絮叨叨
手写RPC(二) 碎碎念
手写RPC(三) 基础结构搭建
手写RPC(四) 核心模块网络协议模块编写 ---- netty服务端
手写RPC(五) 核心模块网络协议模块编写 ---- 自定义协议
手写RPC(六) 核心模块网络协议模块编写 ---- 实现编解码器
手写RPC(七) 核心模块网络协议模块编写 ---- 实现客户端
手写RPC(九) 测试
手写RPC(十) 优化
关于 LengthFieldBasedFrameDecoder 不得不说的事

猜你喜欢

转载自blog.csdn.net/hxj413977035/article/details/121605912