netty手写rpc框架

原理和思想
1.当前生产者会把接口信息注册到zk(注册中心)上去,路径是以com.shanhe.api.service.UserService 下面是多个地址 ,存储结构是像存储结构分析那样注册的, 消费者通过com.shanhe.api.service.UserService 这样的路径去访问userService多个调用接口地址,再通过本地负载均衡算法 选用一个地址,选择到一个地址之后 这个时候订单服务再去拼接一下 调用到哪个接口和哪个方法,会员服务收到这个地址之后 去做解析 通过userService找到它对应的实现 再通过java的反射机制执行到GetUser方法。getUser方法执行完毕 再把结果 生产者发送给消费者
 
1.服务注册
存储结构分析:
com.shanhe.service.api.MemberService
--providers
----shanherpc://127.0.0.1:8080
----shanherpc://127.0.0.1:8081
2.消费者会根据com.shanhe.service.api.MemberService
去到zk上获取接口的调用地址.
----shanherpc://127.0.0.1:8080
----shanherpc://127.0.0.1:8081
自定义rpc注解
package com.shanhe.annotation;

import java.lang.annotation.*;

/**
 * 自定义rpc注解
 */
@Documented
@Inherited
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface RpcAnnotation {
    Class value();
}

公共api接口

package com.shanhe.api;

public interface MemberService {
    String getUser(Long userId);

    int delUser(Long userId);
}

实现

package com.shanhe.api.impl;


import com.shanhe.dubbo.RpcAnnotation;
import com.shanhe.service.api.MemberService;

@RpcAnnotation(MemberService.class)
public class MemberServiceImpl implements MemberService {
    public String getUser(Long userId) {
        return "userId=1";
    }

    public int delUser(Long userId) {
        return 1;
    }
}

服务注册

package com.shanhe.register;

import org.I0Itec.zkclient.ZkClient;


/**
 * 将服务注册到zk上
 */
public class ServiceRegistration {

    /**
     * zk连接地址
     */
    private final String zkServers = "127.0.0.1";
    /**
     * 会话时间
     */
    private final int connectionTimeout = 5000;
    /***
     * zkClient
     */
    private ZkClient zkClient;

    private String rootNamePath = "/shanherpc";

    public ServiceRegistration() {
        // 1.创建zk连接
        zkClient = new ZkClient(zkServers, connectionTimeout);
    }

    public void registr(String serviceName, String addres) {
        // 路径:/shanherpc
        if (!zkClient.exists(rootNamePath)) {
            zkClient.createPersistent(rootNamePath);
        }
        ///shanherpc/com.shanhe.service.api.MemberService
        String serviceNode = rootNamePath + "/" + serviceName;
        if (!zkClient.exists(serviceNode)) {
            zkClient.createPersistent(serviceNode);
        }
        //shanherpc/com.shanhe.service.api.MemberService/providers
        String providers = serviceNode + "/providers";
        if (!zkClient.exists(providers)) {
            zkClient.createPersistent(providers);
        }
        //shanherpc/com.shanhe.service.api.MemberService/providers//shanherpc://127.0.0.1:9001
        String servicePathAddres = providers + "/" + addres;
        if (zkClient.exists(servicePathAddres)) {
            zkClient.delete(servicePathAddres);
        }
        // 临时节点缓存地址
        zkClient.createEphemeral(servicePathAddres);
    }

}

服务发现

package com.shanhe.consumer;

import org.I0Itec.zkclient.ZkClient;

import java.util.List;


/**
 * 服务发现
 */
public class ServiceDiscover {
    /**
     * zk连接地址
     */
    private final String zkServers = "127.0.0.1";
    /**
     * 会话时间
     */
    private final int connectionTimeout = 5000;
    /***
     * zkClient
     */
    private ZkClient zkClient;


    private String rootNamePath = "/shanherpc";

    public ServiceDiscover() {
        // 1. 连接zk连接
        zkClient = new ZkClient(zkServers, connectionTimeout);
    }


    public List<String> getDiscover(String serviceName) {
        List<String> children = zkClient.getChildren(rootNamePath + "/" + serviceName + "/providers");
        return children;
    }

}

 

server端

package com.shanhe.register;


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 org.apache.commons.lang3.StringUtils;
import com.shanhe.ioc.RpContainer;
import com.shanhe.req.RpcRequest;

import java.lang.reflect.Method;



public class RpcNettyServer {

    public void bind(int port) throws InterruptedException {
        EventLoopGroup boss = new NioEventLoopGroup();
        EventLoopGroup worker = new NioEventLoopGroup();
        try {
            ServerBootstrap b = new ServerBootstrap();
            b.group(boss, worker)
                    .channel(NioServerSocketChannel.class)
                    .option(ChannelOption.SO_BACKLOG, 1280)
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel ch) throws Exception {
                            // 新增Marshaling编码器
                            ch.pipeline().addLast(
                                    MarshallingCodeCFactory.buildMarshallingDecoder()
                            );
                            ch.pipeline().addLast(
                                    MarshallingCodeCFactory.buildMarshallingEncoder()
                            );
                            ch.pipeline().addLast(
                                    new ServerHandler()
                            );
                        }
                    });

            ChannelFuture f = b.bind(port).sync();

            f.channel().closeFuture().sync();
        } finally {
            boss.shutdownGracefully();
            worker.shutdownGracefully();
        }
    }

    /**
     * 通过反射执行方法
     */
    @ChannelHandler.Sharable
    public class ServerHandler extends ChannelInboundHandlerAdapter {
        @Override
        public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
//            com.shanhe.service.api.MemberService.getUser(Int)
            RpcRequest rpcRequest = (RpcRequest) msg;
            String className = rpcRequest.getClassName();
            if (StringUtils.isEmpty(className)) {
                return;
            }
            // 从容器中查找到
            Object objectImpl = RpContainer.get(className);
            if (objectImpl == null) {
                return;
            }
            //className 反射机制
            String methodName = rpcRequest.getMethodName();
            Method method = objectImpl.getClass().getMethod(methodName, rpcRequest.getParameterTypes());
            // 真正调用实现类方法
            Object result = method.invoke(objectImpl, rpcRequest.getParamsValue());
            // 返回结果给消费者
            ctx.writeAndFlush(result);
        }


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

将服务绑定到zk

package com.shanhe.register;


import com.shanhe.annotation.RpcAnnotation;
import com.shanhe.ioc.RpContainer;

import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;

/**
 *
 * 将服务绑定到zk
 * 启动netty服务实现监听
 *
 */
public class ShanHeRpcServer {

    /**
     * host
     */
    private String host;
    /**
     * 端口号
     */
    private int port;

    private ServiceRegistration zkServiceRegistration;
    private RpcNettyServer rpcNettyServer;

    public ShanHeRpcServer(String host, int port) {
        this.host = host;
        this.port = port;
        zkServiceRegistration = new ServiceRegistration();
        rpcNettyServer = new RpcNettyServer();
    }

    // 需要发布服务
    public ShanHeRpcServer bind(Object object) throws UnsupportedEncodingException {
        // object MemberServiceImpl
        // 1.需要将该接口注册到zk上
        RpcAnnotation declaredAnnotation = object.getClass().getDeclaredAnnotation(RpcAnnotation.class);
        //com.shanhe.service.api.MemberService
        String sericeName = declaredAnnotation.value().getName();
        String addres = URLEncoder.encode("shanherpc://" + host + ":" + port, "UTF-8");
        zkServiceRegistration.registr(sericeName, addres);
        // 2.将对应接口的实现类注册到容器中
        //    com.shanhe.service.api.MemberService
        RpContainer.put(sericeName, object);
        return this;
    }

    public void start() throws InterruptedException {
        // 2.启动一个netty服务器端监听消费者发送的消息
        rpcNettyServer.bind(port);
    }
}

 

定义容器

package com.shanhe.ioc;

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


/**
 * 容器用来装接口的实现类
 */
public class RpContainer {
    private  static  Map<String, Object> containers = new HashMap<>();

    public  static  void put(String key, Object value) {
        containers.put(key, value);
    }

    public static  Object get(String key) {
        return containers.get(key);
    }
}
传送Request的实体类
package com.shanhe.req;

import java.io.Serializable;

/**
 * 传送Request的实体类
 */
public class RpcRequest implements Serializable {
    private static final long SerialVersionUID = 1L;
    // shanherpc://192.168.1.1:8080/com.shanhe.api.UserService.getUser
    /**
     * 类的className
     */
    private String className;
    /**
     * 方法名称
     */
    private String methodName;
    /**
     * 参数类型
     */
    Class<?> parameterTypes[];
    /**
     * 参数value
     */
    Object paramsValue[];

    public RpcRequest(String className, String methodName, Class<?>[] parameterTypes, Object[] paramsValue) {
        this.className = className;
        this.methodName = methodName;
        this.parameterTypes = parameterTypes;
        this.paramsValue = paramsValue;
    }

    public String getClassName() {
        return className;
    }

    public String getMethodName() {
        return methodName;
    }

    public Class<?>[] getParameterTypes() {
        return parameterTypes;
    }

    public Object[] getParamsValue() {
        return paramsValue;
    }

    public void setClassName(String className) {
        this.className = className;
    }

    public void setMethodName(String methodName) {
        this.methodName = methodName;
    }

    public void setParameterTypes(Class<?>[] parameterTypes) {
        this.parameterTypes = parameterTypes;
    }

    public void setParamsValue(Object[] paramsValue) {
        this.paramsValue = paramsValue;
    }

    @Override
    public String toString() {
        return className + "," + methodName + "," + parameterTypes + paramsValue;
    }
}

客户端通过代理模式执行方法

package com.shanhe.consumer;


import com.shanhe.ioc.RpContainer;
import com.shanhe.register.MarshallingCodeCFactory;
import com.shanhe.req.RpcRequest;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;


import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.net.InetSocketAddress;
import java.net.URLDecoder;
import java.util.List;
import java.util.concurrent.CountDownLatch;

/**
 * 客户端通过代理模式执行方法
 */
public class RpcClientProxy {

    private ServiceDiscover serviceDiscover = new ServiceDiscover();

    public <T> T create(Class<T> tClass) {
        return (T) Proxy.newProxyInstance(tClass.getClassLoader(), new Class[]{tClass}, new InvocationHandler() {

            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                String serviceName = tClass.getName();
                // 1. 根据服务名称 去zk上获取接口调用地址 shanherpc://127.0.0.1:8080
                List<String> discover = serviceDiscover.getDiscover(serviceName);
                //shanherpc://127.0.0.1:8080
                String addres = discover.get(0);
                RpcRequest rpcRequest = new RpcRequest(
                        serviceName, method.getName(), method.getParameterTypes(), args
                );
                // 2.拼接调用接口地址shanherpc://127.0.0.1:8080/com.shanhe.service.api.MemberService getgetUser(1)  tClass.getName
                // 3.使用nettyclient向netty服务器端发送消息
                String[] splitAddres = URLDecoder.decode(addres, "UTF-8").split(":");
                String host = splitAddres[1].replace("//","");
                String port = splitAddres[2];
                return sendMsg(host, Integer.parseInt(port), rpcRequest);
            }
        });
    }

    public Object sendMsg(String host, int port, RpcRequest rpcRequest) {

        DubboClientHandler dubboClientHandler = new DubboClientHandler();
        //创建nioEventLoopGroup
        NioEventLoopGroup group = new NioEventLoopGroup();
        Bootstrap bootstrap = new Bootstrap();
        bootstrap.group(group).channel(NioSocketChannel.class)
                .remoteAddress(new InetSocketAddress(host, port))
                .handler(new ChannelInitializer<SocketChannel>() {
                    @Override
                    protected void initChannel(SocketChannel ch) throws Exception {
                        ch.pipeline().addLast(MarshallingCodeCFactory.buildMarshallingDecoder());
                        ch.pipeline().addLast(MarshallingCodeCFactory.buildMarshallingEncoder());
                        ch.pipeline().addLast(dubboClientHandler);
                    }
                });
        try {
            // 发起同步连接
            ChannelFuture sync = bootstrap.connect().sync();
            sync.channel().writeAndFlush(rpcRequest);
            countDownLatch.await();
        } catch (Exception e) {
            e.printStackTrace();

        } finally {
            group.shutdownGracefully();
        }
        return dubboClientHandler.getResponse();

    }

    private CountDownLatch countDownLatch = new CountDownLatch(1);

    public class DubboClientHandler extends ChannelInboundHandlerAdapter {
        private Object response;

        @Override
        public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
            System.out.println("消费者获取到消息:" + msg);
            this.response = msg;
            countDownLatch.countDown();
            ;
        }


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

        public Object getResponse() {
            return this.response;
        }
    }


}

启动server演示下

 

posted @ 2023-02-06 16:25  山河永慕~  阅读(34)  评论(0编辑  收藏  举报