RPC起步

作者: 叫我宫城大人 | 来源:发表于2018-03-19 18:32 被阅读26次

    一、RPC?

    RPC(Remote Procedure Call),远程过程调用协议,采用C/S模型,请求程序就是一个client,服务提供程序就是一个server。client请求调用server的某个方法,由于不在同一个内存空间,不能直接调用,需要解决下列三个问题:

    1. 网络传输
      客户端和服务端之间建立TCP连接;
    2. 寻址问题
      调用的服务器的主机或IP地址,端口;
    3. 序列化和反序列化
      网络协议基于二进制;

    二、RMI?

    RMI(Remote Method Invoke),是RPC协议的Java具体实现。创建一个RMI程序需要以下五个基本步骤;

    1. 创建远程接口,继承Remote接口,每个方法必须抛出RemoteException异常;

    package com.cjt.rpc;
    
    import java.rmi.Remote;
    import java.rmi.RemoteException;
    
    public interface Service extends Remote {
    
        void say(String message) throws RemoteException;
    }
    

    2. 创建实现类,继承UnicastRemoteObject类,实现远程接口;

    package com.cjt.rpc;
    
    import java.rmi.RemoteException;
    import java.rmi.server.UnicastRemoteObject;
    
    public class ServiceImpl extends UnicastRemoteObject implements Service {
    
        public ServiceImpl() throws RemoteException {
        }
    
        @Override
        public void say(String message) throws RemoteException {
            System.out.println(message);
        }
    }
    

    3. 创建服务器程序,在rmi registry注册表中注册远程对象;

    package com.cjt.rpc;
    
    import javax.naming.Context;
    import javax.naming.InitialContext;
    import javax.naming.NamingException;
    import java.io.IOException;
    import java.rmi.registry.LocateRegistry;
    
    public class Server {
    
        public static void main(String[] args) {
            try {
                LocateRegistry.createRegistry(6666);
                Context context = new InitialContext();
                Service service = new ServiceImpl();
                context.bind("rmi://localhost:6666/service", service);
                // 防止程序结束
                System.in.read();
            } catch (NamingException | IOException e) {
                e.printStackTrace();
            }
        }
    }
    

    4. 创建客户端程序,负责定位远程对象,并且调用远程方法;

    package com.cjt.rpc;
    
    import javax.naming.Context;
    import javax.naming.InitialContext;
    import javax.naming.NamingException;
    import java.rmi.RemoteException;
    
    public class Client {
    
        public static void main(String[] args) {
            try {
                Context context = new InitialContext();
                Service service = (Service) context.lookup("rmi://localhost:6666/service");
                service.say("我来了~");
            } catch (NamingException | RemoteException e) {
                e.printStackTrace();
            }
        }
    }
    

    先运行server端后注册RMI接口,然后启动client端调用,可以发现输出打在了server端的console中,说明调用成功。

    三、Dubbo?

    Dubbo是阿里的一款优秀的RPC服务框架,与Spring无缝集成。

    下图很好说明了Dubbo的架构:

    image.png

    1. 简单起步,首先引入dubbo的pom;

    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>dubbo</artifactId>
        <version>2.5.3</version>
    </dependency>
    

    2. 编写远程服务接口;

    package com.cjt;
    
    public interface DemoService {
    
        void say(String message);
    }
    

    3. 编写实现类;

    package com.cjt;
    
    public class DemoServiceImpl implements DemoService {
    
        @Override
        public void say(String message) {
            System.out.println(message);
        }
    }
    

    4. 编写provider.xml和server端;

    服务端配置文件:

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
           xsi:schemaLocation="http://www.springframework.org/schema/beans
            http://www.springframework.org/schema/beans/spring-beans.xsd
            http://code.alibabatech.com/schema/dubbo
            http://code.alibabatech.com/schema/dubbo/dubbo.xsd">
        <dubbo:application name="hello-world-app"/>
        <dubbo:registry address="multicast://224.5.6.7:1234"/>
        <dubbo:protocol name="dubbo" port="20880"/>
        <dubbo:service interface="com.cjt.DemoService" ref="demoService"/>
    
        <bean id="demoService" class="com.cjt.DemoServiceImpl"/>
    </beans>
    

    server端测试代码:

    package com.cjt;
    
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    
    import java.io.IOException;
    
    public class Server {
    
        public static void main(String[] args) {
            ApplicationContext context = new ClassPathXmlApplicationContext("classpath:provider.xml");
            try {
                // 防止程序结束
                System.in.read();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    

    5. 编写consumer.xml和client端;

    消费端配置文件:

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
           xsi:schemaLocation="http://www.springframework.org/schema/beans
            http://www.springframework.org/schema/beans/spring-beans.xsd
            http://code.alibabatech.com/schema/dubbo
            http://code.alibabatech.com/schema/dubbo/dubbo.xsd">
        <!-- 提供方应用信息,用于计算依赖关系 -->
        <dubbo:application name="hello-world-app"  />
        <!-- 使用multicast广播注册中心暴露服务地址 -->
        <dubbo:registry address="multicast://224.5.6.7:1234" />
        <!-- 用dubbo协议在20880端口暴露服务 -->
        <dubbo:protocol name="dubbo" port="20880" />
        <!-- 生成远程服务代理,可以和本地bean一样使用demoService -->
        <dubbo:reference id="demoService" interface="com.cjt.DemoService" />
    </beans>
    

    client端测试代码:

    package com.cjt;
    
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    
    public class Client {
    
        public static void main(String[] args) {
            ApplicationContext context = new ClassPathXmlApplicationContext("classpath:consumer.xml");
            DemoService service = (DemoService) context.getBean("demoService");
            service.say("我来了~");
        }
    }
    

    可以先运行server端注册接口服务后,然后再运行client端调用接口方法,测试正常。

    四、RPC VS HTTP?

    严格来讲,RPC与HTTP并不是一个层级的概念。HTTP本身也可以作为RPC的传输层协议。

    RPC框架作为分布式的核心,具有以下优点:

    1. 独立服务,分布式响应,减小服务端压力;
    2. 统一接口监控,贴合SOA;
    3. 各个服务隔离,系统解耦;

    五、参考文章

    1. 谁能用通俗的语言解释一下什么是 RPC 框架?
    2. dubbo入门手册

    相关文章

      网友评论

        本文标题:RPC起步

        本文链接:https://www.haomeiwen.com/subject/vxulqftx.html