Dubbo源码学习01

RPC框架的实现原理

服务暴露方通过Socket接受到服务消费方的请求方法调用,通过反序列化解析出消费方调用的方法、参数,通过反射调用服务实现类的方法获取方法调用的结果,将调用结果使用socket回写给服务消费方。

服务消费方通过动态代理透明的对服务进行调用,其中代理对象的方法调用通过socket将方法、参数相关信息写给服务暴露方,在通过socket将暴露方的调用结果回写给消费者

使用Netty实现一个简单的RPC框架

服务暴露Export.java

package ning.zhou.rpc.netty.rpc;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.serialization.ClassResolvers;
import io.netty.handler.codec.serialization.ObjectDecoder;
import io.netty.handler.codec.serialization.ObjectEncoder;

import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

/**
 * @author 周宁
 * @Date 2019-10-10 15:48
 */
public class Export {
    /**
     * 已注册服务
     */
    private Map<Class, Object> registried = new HashMap<>();

    public void setRegistried(Map<Class, Object> registried) {
        this.registried = registried;
    }

    public void export(int port) {
        ServerBootstrap serverBootstrap = new ServerBootstrap();
        EventLoopGroup bossGroup = new NioEventLoopGroup();
        try {
            serverBootstrap.group(bossGroup)
                    .channel(NioServerSocketChannel.class)
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel channel) throws Exception {
                            channel.pipeline().addLast(new ObjectDecoder(1024, ClassResolvers
                                    .cacheDisabled(this.getClass().getClassLoader())));
                            channel.pipeline().addLast(new ObjectEncoder());
                            channel.pipeline().addLast(new SimpleChannelInboundHandler<Invoker>() {
                                @Override
                                protected void channelRead0(ChannelHandlerContext channelHandlerContext, Invoker invoker) throws Exception {
                                    Object obj = registried.get(invoker.getClss());
                                    Class<?>[] parameterTypes = invoker.getParameterTypes();
                                    Object[] arguments = invoker.getArguments();
                                    String methodName = invoker.getMethodName();
                                    Method method = obj.getClass().getMethod(methodName, parameterTypes);
                                    Object result = method.invoke(obj, arguments);
                                    channelHandlerContext.writeAndFlush(result);
                                }
                            });
                        }
                    });
            ChannelFuture f = serverBootstrap.bind(port).sync();
            f.channel().closeFuture().sync();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            bossGroup.shutdownGracefully();
        }
    }
}

服务引用Refer.java

package ning.zhou.rpc.netty.rpc;

import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.serialization.ClassResolvers;
import io.netty.handler.codec.serialization.ObjectDecoder;
import io.netty.handler.codec.serialization.ObjectEncoder;

import java.lang.reflect.Proxy;
import java.util.concurrent.CountDownLatch;

/**
 * @author 周宁
 * @Date 2019-10-10 15:49
 */
public class Refer {

    public static <T> T refer(Class<T> clss, final String host, final int port) {
        return (T) Proxy.newProxyInstance(clss.getClassLoader(), new Class<?>[]{clss}, (proxy, method, args) -> {
            final CountDownLatch countDownLatch = new CountDownLatch(1);
            ResultRefer resultRefer = new ResultRefer();
            EventLoopGroup group = null;
            try {
                group = new NioEventLoopGroup();
                Bootstrap b = new Bootstrap();
                b.group(group).channel(NioSocketChannel.class)
                        .handler(new ChannelInitializer<NioSocketChannel>() {
                            @Override
                            protected void initChannel(NioSocketChannel channel) throws Exception {
                                channel.pipeline().addLast(new ObjectDecoder(1024, ClassResolvers
                                        .cacheDisabled(this.getClass().getClassLoader())));
                                channel.pipeline().addLast(new ObjectEncoder());
                                channel.pipeline().addLast(new ChannelInboundHandlerAdapter() {

                                    @Override
                                    public void channelActive(ChannelHandlerContext ctx) throws Exception {
                                        Invoker invoker = new Invoker();
                                        invoker.setArguments(args);
                                        invoker.setMethodName(method.getName());
                                        invoker.setParameterTypes(method.getParameterTypes());
                                        invoker.setClss(clss);
                                        ctx.writeAndFlush(invoker);
                                    }

                                    @Override
                                    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
                                        resultRefer.setResult(msg);
                                        countDownLatch.countDown();
                                    }
                                });
                            }
                        });
                b.connect(host, port);
                countDownLatch.await();
                return resultRefer.getResult();
            } finally {
                group.shutdownGracefully();
            }
        });
    }

}

保存RPC调用结果的类

package ning.zhou.rpc.netty.rpc;

/**
 * @author 周宁
 * @Date 2019-10-10 18:05
 */
public class ResultRefer {

    private Object result;

    public Object getResult() {
        return result;
    }

    public void setResult(Object result) {
        this.result = result;
    }
}

测试类HelloService.java和HelloServiceImpl.java

package ning.zhou.rpc.rpc;

/**
 * @author 周宁
 * @Date 2019-10-09 13:48
 */
public interface HelloService {

    String hello(String name);
}
package ning.zhou.rpc.rpc;

/**
 * @author 周宁
 * @Date 2019-10-09 13:48
 */
public class HelloServiceImpl implements HelloService {
    @Override
    public String hello(String name) {
        return "hello" + name;
    }
}

编写服务提供者Provider.java

package ning.zhou.rpc.netty.rpc;

import ning.zhou.rpc.rpc.HelloService;
import ning.zhou.rpc.rpc.HelloServiceImpl;

import java.util.HashMap;
import java.util.Map;

/**
 * @author 周宁
 * @Date 2019-10-10 16:31
 */
public class Provider {

    public static void main(String[] args) {
        Export export = new Export();
        Map<Class,Object> serv = new HashMap<>();
        serv.put(HelloService.class,new HelloServiceImpl());
        export.setRegistried(serv);
        export.export(1234);
    }
}

编写服务消费者Consumer.java

package ning.zhou.rpc.netty.rpc;

import ning.zhou.rpc.rpc.HelloService;

/**
 * @author 周宁
 * @Date 2019-10-10 17:04
 */
public class Consumer {

    public static void main(String[] args) throws InterruptedException {
        HelloService helloService = Refer.refer(HelloService.class,"127.0.0.1",1234);
        for(int i = 0;i<Integer.MAX_VALUE;i++){
            String hello = helloService.hello("World" + i);
            System.out.println(hello);
            Thread.sleep(1000);
        }

    }
}

分别启动Provider.java和Consumer.java可以看到控制台有如下输出

代码

 https://github.com/SpringStudent/GyRpc

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值