Netty手写RPC框架

RPC简介

RPC,Remote Procedure Call,远程过程调用,是一种通过网络从远程计算机上请求服务,而不需要了解底层网络技术的协议。

RPC框架实现要求

我们这里要定义一个 RPC 框架,这个框架提供给用户后,用户只需要按照使用步骤就可以完成 RPC 远程调用。我们现在给出用户的使用步骤:
1、 用户需要将业务接口通知到 Server 与 Client,因为业务接口是服务名称。
2、 用户只需将业务接口的实现类写入到 Server 端的指定包下,那么这个包下的实现类就会被 Server 发布。
3、 Client 端只需根据业务接口名就可获取到 Server 端发布的服务提供者,然后就可以调用到远程 Server 端的实现类方法的执行。

代码实现

1、rpc-api包
业务接口:

/**
 * 业务接口
 */
public interface SomeService {
    String hello(String name);
}

客户端发送给服务端的服务调用信息:

/**
 * 客户端发送给服务端的服务调用信息
 */
@Data
public class Invocation implements Serializable {
     // 接口名,即服务名称
    private String className;
     // 远程调用的方法名
    private String methodName;
     // 方法参数类型
    private Class<?>[] paramTypes;
     // 方法参数值
    private Object[] paramValues;
}

2、rpc-server包
业务接口的实现类写入到 Server 端的指定包下:

package com.rpc.server.service;

import com.rpc.api.SomeService;

public class SomeServiceImpl implements SomeService {
    @Override
    public String hello(String name) {
        return "你好:"+name;
    }
}

服务端启动:

public class RpcServerStarter {
    public static void main(String[] args) throws Exception {
        RpcServer server = new RpcServer();
        server.publish("com.rpc.server.service");
        server.start();
    }
}

rpc服务端:

public class RpcServer {

    // 注册表
    private Map<String, Object> registerMap = new HashMap<>();
    // 用于缓存指定包下的实现类的类名
    private List<String> classCache = new ArrayList<>();
    // 线程安全的list
    // private List<String> classCache = Collections.synchronizedList(new ArrayList<>());

    // 将接口名(服务名称)与指定包中的实现类的实例进行对应,即写入到一个map
    public void publish(String basePackage) throws Exception {
        // 将指定包中的实现类的类名写入到classCache中
        cacheProviderClass(basePackage);
        // 真正的注册
        doRegister();
    }

    private void cacheProviderClass(String basePackage) {

        URL resource = this.getClass().getClassLoader()
                // 将包名的.转为/
                .getResource(basePackage.replaceAll("\\.", "/"));

        // 若目录中没有任何资源,则直接结束
        if(resource == null) return;

        // 将URL资源转换为File
        File dir = new File(resource.getFile());
        // 遍历指定包及其子孙包中所有文件,查找.class文件
        for (File file : dir.listFiles()) {
            if (file.isDirectory()) {
                cacheProviderClass(basePackage + "." + file.getName());
            } else if (file.getName().endsWith(".class")) {
                String fileName = file.getName().replace(".class", "").trim();
                classCache.add(basePackage + "." + fileName);
            }
        }

         System.out.println(classCache);
    }

    private void doRegister() throws Exception {

        if (classCache.size() == 0) {
            return;
        }

        // 遍历缓存中的所有类
        for(String className : classCache) {
            Class<?> clazz = Class.forName(className);
            // 获取接口名
            String interfaceName = clazz.getInterfaces()[0].getName();
            registerMap.put(interfaceName, clazz.newInstance());
        }
    }

    // 启动Netty Server
    public void start() throws InterruptedException {
        EventLoopGroup parentGroup = new NioEventLoopGroup();
        EventLoopGroup childGroup = new NioEventLoopGroup();
        try {
            ServerBootstrap bootstrap = new ServerBootstrap();
            bootstrap.group(parentGroup, childGroup)
                    // 用于指定,当服务端的请求处理线程全部用完时,
                    // 临时存放已经完成了三次握手的请求的队列的最大长度。
                    .option(ChannelOption.SO_BACKLOG, 1024)
                    // 指定是否启用心跳机制来维护长连接的不被清除
                    .childOption(ChannelOption.SO_KEEPALIVE, true)
                    // 指定要创建Channel的类型
                    .channel(NioServerSocketChannel.class)
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel ch) throws Exception {
                            ChannelPipeline pipeline = ch.pipeline();
                            // 添加编码器
                            pipeline.addLast(new ObjectEncoder());
                            // 添加解码器
                            pipeline.addLast(new ObjectDecoder(Integer.MAX_VALUE,
                                    ClassResolvers.cacheDisabled(null)));
                            // 添加自定义处理器
                            pipeline.addLast(new RpcServerHandler(registerMap));
                        }
                    });
            ChannelFuture future = bootstrap.bind(8888).sync();
            System.out.println("微服务已经注册完成。。。");
            future.channel().closeFuture().sync();
        } finally {
            parentGroup.shutdownGracefully();
            childGroup.shutdownGracefully();
        }
    }
}

服务端handler:

public class RpcServerHandler extends SimpleChannelInboundHandler<Invocation> {

    private Map<String, Object> registerMap;

    public RpcServerHandler(Map<String, Object> registerMap) {
        this.registerMap = registerMap;
    }

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, Invocation msg) throws Exception {
        Object result = "没有指定的提供者";
        if (registerMap.containsKey(msg.getClassName())) {
            Object provider = registerMap.get(msg.getClassName());
            result = provider.getClass()
                    .getMethod(msg.getMethodName(), msg.getParamTypes())
                    .invoke(provider, msg.getParamValues());
        }
        ctx.writeAndFlush(result);
        ctx.close();
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        cause.printStackTrace();
        ctx.close();
    }
}

3、客户端包
rpc调用者:

public class RpcConsumer {
    public static void main(String[] args) {
        SomeService service = RpcProxy.create(SomeService.class);
        System.out.println(service.hello("java"));
        System.out.println(service.hashCode());
    }
}

prc代理:

public class RpcProxy {

    // 泛型方法
    public static <T> T create(Class<?> clazz) {
        return (T) Proxy.newProxyInstance(clazz.getClassLoader(),
                new Class[]{clazz},
                new InvocationHandler() {
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        // 若调用的是Object的方法,则直接进行本地调用
                        if (Object.class.equals(method.getDeclaringClass())) {
                            return method.invoke(this, args);
                        }

                        // 进行远程调用
                        return rpcInvoke(clazz, method, args);
                    }
                });
    }

    private static Object rpcInvoke(Class<?> clazz, Method method, Object[] args) throws InterruptedException {
        RpcClientHandler handler = new RpcClientHandler();
        NioEventLoopGroup loopGroup = new NioEventLoopGroup();
        try {

            Bootstrap bootstrap = new Bootstrap();
            bootstrap.group(loopGroup)
                    .channel(NioSocketChannel.class)
                    // Nagle算法开关,关闭Nagle算法
                    .option(ChannelOption.TCP_NODELAY, true)
                    .handler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel ch) throws Exception {
                            ChannelPipeline pipeline = ch.pipeline();
                            // 添加编码器
                            pipeline.addLast(new ObjectEncoder());
                            // 添加解码器
                            pipeline.addLast(new ObjectDecoder(Integer.MAX_VALUE,
                                    ClassResolvers.cacheDisabled(null)));
                            // 添加自定义处理器
                            pipeline.addLast(handler);
                        }
                    });

            ChannelFuture future = bootstrap.connect("localhost", 8888).sync();

            // 将调用信息传递给Netty Server
            Invocation invocation = new Invocation();
            invocation.setClassName(clazz.getName());
            invocation.setMethodName(method.getName());
            invocation.setParamTypes(method.getParameterTypes());
            invocation.setParamValues(args);

            future.channel().writeAndFlush(invocation).sync();
            Object result = handler.getResult();
            future.channel().closeFuture().sync();
        } finally {
            loopGroup.shutdownGracefully();
        }
        return handler.getResult();
    }
}

客户端handler:

public class RpcClientHandler extends SimpleChannelInboundHandler<Object> {
    private Object result;

    public Object getResult() {
        return this.result;
    }
    // msg是服务端传递来的远程调用的结果
    @Override
    protected void channelRead0(ChannelHandlerContext ctx, Object msg) throws Exception {
        this.result = msg;
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        cause.printStackTrace();
        ctx.close();
    }
}

4、执行结果:
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值