栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

手写RPC框架笔记(5)

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

手写RPC框架笔记(5)

RPC Version 5

引入了 zookeeper 作为服务注册中心,修改掉以前本地使用Map存储服务的方式。
下载zookeeper
需要修改 conf 下的 zoo_sample.cfg,复制一份改名为zoo.cfg,修改里面的 dataDir 路径,改为一个真实存在的路径,如果是windows复制的全路径名 要把 " " 改为 " / " ,然后保存。
接下来在项目引入 Curator 依赖 和 Log4j 依赖 :



    org.apache.curator
    curator-recipes
    5.2.1




    org.apache.logging.log4j
    log4j-core
    2.17.1

还是需要先了解一下zookeeper 和 使用 curator 搭建zookeeper客户端:
Curator 学习
zookeeper 学习
漫画版了解zookeeper

开始新增一个注册中心接口:
注册方法 和 服务发现

public interface ServiceRegister {
    void register(String serviceName, InetSocketAddress serverAddress);
    InetSocketAddress serviceDiscovery(String serviceName);
}

实现zookeeper注册中心:

public class ZKServiceRegister implements ServiceRegister{
    // curator 提供的zookeeper客户端
    private CuratorFramework client;
    // zookeeper根路径节点
    private static final String ROOT_PATH = "MyRPC";

    // zookeeper客户端初始化,与zookeeper服务端建立连接
    public ZKServiceRegister(){
        // 指数时间重试
        RetryPolicy policy = new ExponentialBackoffRetry(1000, 3);
        // zookeeper的地址固定,不管是服务提供者还是,消费者都要与之建立连接
        // sessionTimeoutMs 与 zoo.cfg中的tickTime 有关系,
        // zk还会根据minSessionTimeout与maxSessionTimeout两个参数重新调整最后的超时值。默认分别为tickTime 的2倍和20倍
        // 使用心跳监听状态
        this.client = CuratorFrameworkFactory.builder().connectString("127.0.0.1:2181")
                .sessionTimeoutMs(40000).retryPolicy(policy).namespace(ROOT_PATH).build();
        this.client.start();
        System.out.println("zookeeper 连接成功!");
    }

    @Override
    public void register(String serviceName, InetSocketAddress serverAddress) {
        try {
            // serviceName创建成永久节点,服务提供者下线时,不删服务名,只删地址
            if(client.checkExists().forPath("/" + serviceName) == null){
                client.create().creatingParentsIfNeeded().withMode(CreateMode.PERSISTENT).forPath("/" + serviceName);
            }
            // 路径地址,一个 / 代表一个节点
            String path = "/" + serviceName + "/" + getServiceAddress(serverAddress);
            // 临时节点,服务器下线就删除节点
            client.create().creatingParentsIfNeeded().withMode(CreateMode.EPHEMERAL).forPath(path);
        } catch (Exception e) {
            System.out.println("此服务已存在");
        }
    }

    // 根据服务名返回地址
    @Override
    public InetSocketAddress serviceDiscovery(String serviceName) {
        List strings = null;
        try {
            strings = client.getChildren().forPath("/" + serviceName);
            // 默认用第一个
            String s = strings.get(0);
            return parseAddress(s);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    // 地址转字符串
    private String getServiceAddress(InetSocketAddress serverAddress){
        return serverAddress.getHostName() + ":" + serverAddress.getPort();
    }

    // 字符串解析为地址
    private InetSocketAddress parseAddress(String address){
        String[] res = address.split(":");
        return new InetSocketAddress(res[0],Integer.parseInt(res[1]));
    }
}

同时需要改一下 client的构造方法,使其在 sendRequest() 中注册服务:
NettyClient:

	// 新增属性
    private ServiceRegister serviceRegister;

    // 初始化注册中心
    public NettyRPCClient(){
        this.serviceRegister = new ZKServiceRegister();
    }

sendRequest 方法添加:

        // 从注册中心获取host port
        InetSocketAddress address = serviceRegister.serviceDiscovery(request.getInterfaceName());
        host = address.getHostName();
        port = address.getPort();

SimpleRPCClient 同样方式修改。

需要修改一下服务提供方法 ServiceProvider:

public class ServiceProvider {

    private Map interfaceProvider;
    private ServiceRegister serviceRegister;
    private String host;
    private int port;

    public ServiceProvider(String host,int port) {
        this.host = host;
        this.port = port;
        this.interfaceProvider = new HashMap<>();
        this.serviceRegister = new ZKServiceRegister();
    }

    public Map getProvide() {
        return this.interfaceProvider;
    }

    public void provideServiceInterface(Object service) {
        Class[] interfaces = service.getClass().getInterfaces();

        for (Class clazz : interfaces) {
            //本机的映射表map
            interfaceProvider.put(clazz.getName(), service);
            // 在注册中心注册服务
            serviceRegister.register(clazz.getName(),new InetSocketAddress(host,port));
        }
    }

    public Object getService(String interfaceName) {
        return interfaceProvider.get(interfaceName);
    }

}

大功告成!
下篇使用负载均衡。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/992030.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号