真的够可以的,基于Netty实现了RPC框架( 三 )

在这里还通过反射实现了简易的IOC容器,先递归扫描provider包底下的类,把这些类的对象作为服务对象放到IOC容器中进行管理,由于IOC是一个Map实现的,所以将类名作为服务名称,也就是Key,服务对象作为Value 。根据消费者传过来的服务名称,就可以找到对应的服务,到此,Registry和Provider已经全部写完了 。
2、consumer
目录结构如下:
└─src├─main│├─java││└─edu││└─xpu││└─rpc││├─api│││IRpcCalc.java│││IRpcHello.java│││││├─consumer││││RpcConsumer.java│││││││└─proxy│││RpcProxy.java│││RpcProxyHandler.java│││││└─core││InvokerMessage.java│││└─resources└─test└─java└─ pom.xml在看客户端的实现之前,先梳理一下RPC流程 。API 模块中的接口只在服务端实现了 。因此,客户端调用API 中定义的某一个接口方法时,实际上是要发起一次网络请求去调用服务端的某一个服务 。而这个网络请求首先被注册中心接收,由注册中心先确定需要调用的服务的位置,再将请求转发至真实的服务实现,最终调用服务端代码,将返回值通过网络传输给客户端 。整个过程对于客户端而言是完全无感知的,就像调用本地方法一样,所以必定要对客户端的API接口做代理,隐藏网络请求的细节 。

真的够可以的,基于Netty实现了RPC框架

文章插图
 
由上图的流程图可知,要让用户调用无感知,必须创建出代理类来完成网络请求的操作 。
RpcProxy.java如下:
public class RpcProxy {public static <T> T create(Class<?> clazz) {//clazz传进来本身就是interfaceMethodProxy proxy = new MethodProxy(clazz);T result = (T) Proxy.newProxyInstance(clazz.getClassLoader(), new Class[]{clazz} , proxy);return result;}private static class MethodProxy implements InvocationHandler {private Class<?> clazz;public MethodProxy(Class<?> clazz) {this.clazz = clazz;}public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {// 如果传进来是一个已实现的具体类if (Object.class.equals(method.getDeclaringClass())) {try {return method.invoke(this, args);} catch (Throwable t) {t.printStackTrace();}// 如果传进来的是一个接口(核心)} else {return rpcInvoke(method, args);}return null;}// 实现接口的核心方法public Object rpcInvoke(Method method, Object[] args) {// 传输协议封装InvokerMessage invokerMessage = new InvokerMessage();invokerMessage.setClassName(this.clazz.getName());invokerMessage.setMethodName(method.getName());invokerMessage.setValues(args);invokerMessage.setParams(method.getParameterTypes());final RpcProxyHandler consumerHandler = new RpcProxyHandler();EventLoopGroup group = new NioEventLoopGroup();try {Bootstrap bootstrap = new Bootstrap();bootstrap.group(group).channel(NioSocketChannel.class).option(ChannelOption.TCP_NODELAY, true).handler(new ChannelInitializer<SocketChannel>() {@Overridepublic void initChannel(SocketChannel ch) throws Exception {ChannelPipeline pipeline = ch.pipeline();pipeline.addLast("frameDecoder", new LengthFieldBasedFrameDecoder(Integer.MAX_VALUE, 0, 4, 0, 4));//自定义协议编码器pipeline.addLast("frameEncoder", new LengthFieldPrepender(4));//对象参数类型编码器pipeline.addLast("encoder", new ObjectEncoder());//对象参数类型解码器pipeline.addLast("decoder", new ObjectDecoder(Integer.MAX_VALUE, ClassResolvers.cacheDisabled(null)));pipeline.addLast("handler", consumerHandler);}});ChannelFuture future = bootstrap.connect("localhost", 8080).sync();future.channel().writeAndFlush(invokerMessage).sync();future.channel().closeFuture().sync();} catch (Exception e) {e.printStackTrace();} finally {group.shutdownGracefully();}return consumerHandler.getResponse();}}}我们通过传进来的接口对象,获得了要调用的服务名,服务方法名,参数类型列表,参数列表,这样就把自定义的RPC协议包封装好了,只需要把协议包发出去等待结果返回即可,所以为了接收返回值数据还需要自定义一个接收用的Handler,RpcProxyHandlerdiamante如下:
public class RpcProxyHandler extends ChannelInboundHandlerAdapter {private Object result;public Object getResponse() {return result;}@Overridepublic void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {result = msg;}@Overridepublic void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {System.out.println("client exception is general");}}这样就算是完成了整个流程,下面开始测试一下吧,测试的RpcConsumer.java代码如下:
public class RpcConsumer {public static void main(String[] args) {// 本机之间的正常调用// IRpcHello iRpcHello = new RpcHelloProvider();// iRpcHello.hello("Tom");// 肯定是用动态代理来实现的// 传给它接口,返回一个接口的实例,伪代理IRpcHello rpcHello = RpcProxy.create(IRpcHello.class);System.out.println(rpcHello.hello("ZouChangLin"));int a = 10;int b = 5;IRpcCalc iRpcCalc = RpcProxy.create(IRpcCalc.class);System.out.println(String.format("%d + %d = %d", a, b, iRpcCalc.add(a, b)));System.out.println(String.format("%d - %d = %d ", a, b, iRpcCalc.sub(a, b)));System.out.println(String.format("%d * %d = %d", a, b, iRpcCalc.mul(a, b)));System.out.println(String.format("%d / %d = %d", a, b, iRpcCalc.div(a, b)));}}


推荐阅读