首先,我们的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框架的你是不是稍稍膨胀了一下?当时的我也是这样子的心态!
下节完美开始编写测试代码进行测试。
