20180602-分布式通讯框架RMI的原理.md

TOC

[TOC]

  1. 什么是RPC
  2. RPC框架原理
  3. 了解Java RMI
  4. 基于RMI时间
  5. RMI通讯原理分析
  6. 实现自己的RPC框架

什么是RPC

Remote procedure call

远程过程调用

模块间远程调用的由来.png

集中式到分布式

  • RMI(JRMP) /soap(webservice/axis/cxf) thrift/grpc/dubbo

RPC框架的不断演进,基于TCP/IP协议之上封装了特定的协议通讯就是RMI

RMI

  • Remote method invocation
  • 远程方法调用
  • 纯java的RPC框架
  • JRMP(支持java平台的远程调用)

解决掉序列化、网络通讯、安全检查,把问题全部屏蔽掉。

底层 TCP/IP协议层之上。

两个进程之间的远程调用的步骤.png


序列化

安全性

服务的管理

TCP/IP


  • 实现java RMI

    • 继承 remote
{
   IhelloService helloservice = new HelloServiceImpl();   //已经发布了一个远程对象。
   locateRegistry.createRegistry(1099);
   // 服务端的启动registry的过程
   Return registryImpl;
}

Naming.bind(“rmi://127.0.0.1/Hello0”,helloService); 注册中心,key-value形式。

注册中心是独立的。

源码分析

public Remote exportObject(Remote var1, Object var2, boolean var3) throws RemoteException {
    Class var4 = var1.getClass();

    Remote var5;
    try {
        // 对HeloServiceImpl的代理
        var5 = Util.createProxy(var4, this.getClientRef(), this.forceStubUse);
    } catch (IllegalArgumentException var7) {
        throw new ExportException("remote object implements illegal remote interface", var7);
    }

    if (var5 instanceof RemoteStub) {
        this.setSkeleton(var1);
    }

    //  包装一个暴露在TCP端口上的对象
    Target var6 = new Target(var1, this, var5, this.ref.getObjID(), var3);
    this.ref.exportObject(var6);
    this.hashToMethod_Map = (Map)hashToMethod_Maps.get(var4);
    return var5;
}

public String getClientHost() throws ServerNotActiveException {
    return TCPTransport.getClientHost();
}

public void setSkeleton(Remote var1) throws RemoteException {
    if (!withoutSkeletons.containsKey(var1.getClass())) {
        try {
            this.skel = Util.createSkeleton(var1);
        } catch (SkeletonNotFoundException var3) {
            withoutSkeletons.put(var1.getClass(), (Object)null);
        }
    }

}

服务端的启动Registry的过程

LocateRegistry.createRegistry(1099);

HelloServiceImpl_stub

RegistryImpl_stub

发布HelloServiceImpl 代理对象

构造方法

// 远端调用异常的话,会抛出一个异常
protected HelloServiceImpl() throws RemoteException {
    super();
}

@Override
public String sayHello(String msg) throws RemoteException {
    return "Hello" + msg;
}

Super调用父类UnicastRemoteObject

protected UnicastRemoteObject() throws RemoteException{
    this(0);
}

This(0)调用 发布

protected UnicastRemoteObject(int port) throws RemoteException{
    this.port = port;
    exportObject((Remote) this, port);
}

#ExportObject(remote) 调用 发布

封装了一个UnicastServerRef 发布

public static Remote exportObject(Remote obj, int port) throws RemoteException {
    return exportObject(obj, new UnicastServerRef(port));
}

调用自身

private static Remote exportObject(Remote obj, UnicastServerRef sref) throws RemoteException {
   // if obj extends UnicastRemoteObject, set its ref.
   if (obj instanceof UnicastRemoteObject) {
       ((UnicastRemoteObject) obj).ref = sref;
   }
   return sref.exportObject(obj, null, false);
}

#UnicastSerRerf() 发布

public Remote exportObject(Remote var1, Object var2, boolean var3) throws RemoteException {
    Class var4 = var1.getClass();

    Remote var5;
    try {
        // 创建代理,HelloServerImpl_stu(提供给客户端)
        // JDK老版本需要手动实现 stu  新版本不需要了
        var5 = Util.createProxy(var4, this.getClientRef(), this.forceStubUse);
    } catch (IllegalArgumentException var7) {
        throw new ExportException("remote object implements illegal remote interface", var7);
    }

    if (var5 instanceof RemoteStub) {
        this.setSkeleton(var1);
    }

    Target var6 = new Target(var1, this, var5, this.ref.getObjID(), var3);

    this.ref.exportObject(var6);
    //发布TCP协议的服务

    this.hashToMethod_Map = (Map)hashToMethod_Maps.get(var4);
    return var5;
}

发布 registryImpl 对象

LocateRegistry.createRegistry(1099);

过程如上

  • RegistryImpl_stub 不需要再生成了,已经提供了
  • HelloServiceImpl_stub 需要动态生成字节码,动态的生成一个文件。

暴露

Server
LocateRegistry.createRegistry(1099);
LocateRegistry
public static Registry createRegistry(int port) throws RemoteException {
     return new RegistryImpl(port);
 }
registryImpl
public RegistryImpl(final int var1) throws RemoteException {
    if (var1 == 1099 && System.getSecurityManager() != null) {
        try {
            AccessController.doPrivileged(new PrivilegedExceptionAction<Void>() {
                public Void run() throws RemoteException {
                    LiveRef var1x = new LiveRef(RegistryImpl.id, var1);
                    RegistryImpl.this.setup(new UnicastServerRef(var1x, (var0) -> {
                        return RegistryImpl.registryFilter(var0);
                    }));
                    return null;
                }
            }, (AccessControlContext)null, new SocketPermission("localhost:" + var1, "listen,accept"));
        } catch (PrivilegedActionException var3) {
            throw (RemoteException)var3.getException();
        }
    } else {
        LiveRef var2 = new LiveRef(id, var1);
        this.setup(new UnicastServerRef(var2, RegistryImpl::registryFilter));
    }


RegistryImpl
private void setup(UnicastServerRef var1) throws RemoteException {
     this.ref = var1;
     var1.exportObject(this, (Object)null, true);
 }
UnicastServerRef
public Remote exportObject(Remote var1, Object var2, boolean var3) throws RemoteException {
    Class var4 = var1.getClass();
    Remote var5;
    try {
        var5 = Util.createProxy(var4, this.getClientRef(), this.forceStubUse);
    } catch (IllegalArgumentException var7) {
        throw new ExportException("remote object implements illegal remote interface", var7);
    }
    if (var5 instanceof RemoteStub) {
        this.setSkeleton(var1);
    }
    Target var6 = new Target(var1, this, var5, this.ref.getObjID(), var3);
    this.ref.exportObject(var6);
    this.hashToMethod_Map = (Map)hashToMethod_Maps.get(var4);
    return var5;
}
LiveRef
public void exportObject(Target var1) throws RemoteException {
     this.ep.exportObject(var1);
 }
Endpoint
void exportObject(Target var1) throws RemoteException;
TCPEndpoint
public void exportObject(Target var1) throws RemoteException {
    this.transport.exportObject(var1);
}
TCPTransport 最终暴露服务
public void exportObject(Target var1) throws RemoteException {
    synchronized(this) {
        this.listen();
        ++this.exportCount;
    }
    boolean var2 = false;
    boolean var12 = false;
    try {
         var12 = true;
         super.exportObject(var1);
         var2 = true;
         var12 = false;
     } finally {
         if (var12) {
             if (!var2) {
                 synchronized(this) {
                     this.decrementExportCount();
                 }
             }
         }
     }
     if (!var2) {
         synchronized(this) {
             this.decrementExportCount();
         }
     }
 }

TCPTransport 中的 new listen() 创建了一个new server()

  • 工厂模式
  • 模板模式

客户端获取服务端的代理

就是stub对象

获得 HelloServiceImpl_stub 、 RegisterImpl_stub

客户端获取的一定是个proxy

IHelloService helloService = (IHelloService) Naming.lookup("rmi://127.0.0.1/hello");
// HelloServiceImpl实例(HelloServiceImpl_stub)
// RegistryImpl_stub 

Naming

public static Remote lookup(String name) throws NotBoundException, 
        java.net.MalformedURLException, RemoteException{
    // 解析URL
    ParsedNamingURL parsed = parseURL(name);

    // 得到注册的实例不可能是RegistryImpl ,而应该是regisryImpl_stub
    Registry registry = getRegistry(parsed);
    if (parsed.name == null)
        return registry;
    return registry.lookup(parsed.name);
}

Naming

private static Registry getRegistry(ParsedNamingURL parsed)  throws RemoteException {
    return LocateRegistry.getRegistry(parsed.host, parsed.port);
}

LocateRegistry

public static Registry getRegistry(String host, int port) throws RemoteException{
    return getRegistry(host, port, null);
}

LocateRegistry

public static Registry getRegistry(String host, int port,
                                   RMIClientSocketFactory csf)
    throws RemoteException
{
    Registry registry = null;
    if (port <= 0)
        port = Registry.REGISTRY_PORT;
    if (host == null || host.length() == 0) {

        try {
            host = java.net.InetAddress.getLocalHost().getHostAddress();
        } catch (Exception e) {
            // If that failed, at least try "" (localhost) anyway...
            host = "";
        }
    }

    LiveRef liveRef =
        new LiveRef(new ObjID(ObjID.REGISTRY_ID),
                    new TCPEndpoint(host, port, csf, null),
                    false);
    RemoteRef ref =
        (csf == null) ? new UnicastRef(liveRef) : new UnicastRef2(liveRef);
    // 创建代理  然后拿到一个代理类
    return (Registry) Util.createProxy*(RegistryImpl.class, ref, false);
}


Utils 创建代理的时候

public static Remote createProxy(Class<?> var0, RemoteRef var1, boolean var2) throws StubNotFoundException {
    Class var3;
    try {
        var3 = getRemoteClass(var0);
    } catch (ClassNotFoundException var9) {
        throw new StubNotFoundException("object does not implement a remote interface: " + var0.getName());
    }

    // 上边已经创建完了
    if (var2 || !ignoreStubClasses && stubClassExists(var3)) {

        // 创建一个createStub
        return createStub(var3, var1);
    } else {
        final ClassLoader var4 = var0.getClassLoader();
        final Class[] var5 = getRemoteInterfaces(var0);
        final RemoteObjectInvocationHandler var6 = new RemoteObjectInvocationHandler(var1);
        try {
            return (Remote)AccessController.doPrivileged(new PrivilegedAction<Remote>() {
                public Remote run() {
                    return (Remote)Proxy.newProxyInstance(var4, var5, var6);
                }
            });
        } catch (IllegalArgumentException var8) {
            throw new StubNotFoundException("unable to create proxy", var8);
        }
    }
}

UnicastRef

public RemoteCall newCall(RemoteObject var1, Operation[] var2, int var3, long var4) throws RemoteException {
    clientRefLog.log(Log.BRIEF, "get connection");
    Connection var6 = this.ref.getChannel().newConnection();
    try {
        clientRefLog.log(Log.VERBOSE, "create call context");
        if (clientCallLog.isLoggable(Log.VERBOSE)) {
            this.logClientCall(var1, var2[var3]);
        }
        StreamRemoteCall var7 = new StreamRemoteCall(var6, this.ref.getObjID(), var3, var4);
        try {
            this.marshalCustomCallData(var7.getOutputStream());
        } catch (IOException var9) {
            throw new MarshalException("error marshaling custom call data");
        }
        return var7;
    } catch (RemoteException var10) {
        this.ref.getChannel().free(var6, false);
        throw var10;
    }
}


TCPChannel

public Connection newConnection() throws RemoteException {
    TCPConnection var1;
    do {
        var1 = null;
        List var2 = this.freeList;
        synchronized(this.freeList) {
            int var3 = this.freeList.size() - 1;
            if (var3 >= 0) {
                this.checkConnectPermission();
                var1 = (TCPConnection)this.freeList.get(var3);
                this.freeList.remove(var3);
            }
        }
        if (var1 != null) {
            if (!var1.isDead()) {
                TCPTransport.tcpLog.log(Log.BRIEF, "reuse connection");
                return var1;
            }
            this.free(var1, false);
        }
    } while(var1 != null);
    return this.createConnection();
}

TCPChannel

private Connection createConnection() throws RemoteException {
    TCPTransport.tcpLog.log(Log.BRIEF, "create connection");
    TCPConnection var1;
    if (!this.usingMultiplexer) {
        Socket var2 = this.ep.newSocket();
        var1 = new TCPConnection(this, var2);
        try {
            DataOutputStream var3 = new DataOutputStream(var1.getOutputStream());
            this.writeTransportHeader(var3);
            if (!var1.isReusable()) {
                var3.writeByte(76);
            } else {
                var3.writeByte(75);
                var3.flush();
                int var4 = 0;
                try {
                    var4 = var2.getSoTimeout();
                    var2.setSoTimeout(handshakeTimeout);
                } catch (Exception var15) {
                    ;
                }
                DataInputStream var5 = new DataInputStream(var1.getInputStream());
                byte var6 = var5.readByte();
                if (var6 != 78) {
                    throw new ConnectIOException(var6 == 79 ? "JRMP StreamProtocol not supported by server" : "non-JRMP server at remote endpoint");
                }
                String var7 = var5.readUTF();
                int var8 = var5.readInt();
                if (TCPTransport.tcpLog.isLoggable(Log.VERBOSE)) {
                    TCPTransport.tcpLog.log(Log.VERBOSE, "server suggested " + var7 + ":" + var8);
                }
                TCPEndpoint.setLocalHost(var7);
                TCPEndpoint var9 = TCPEndpoint.getLocalEndpoint(0, (RMIClientSocketFactory)null, (RMIServerSocketFactory)null);
                var3.writeUTF(var9.getHost());
                var3.writeInt(var9.getPort());
                if (TCPTransport.tcpLog.isLoggable(Log.VERBOSE)) {
                    TCPTransport.tcpLog.log(Log.VERBOSE, "using " + var9.getHost() + ":" + var9.getPort());
                }
                try {
                    var2.setSoTimeout(var4 != 0 ? var4 : responseTimeout);
                } catch (Exception var14) {
                    ;
                }
                var3.flush();
            }
        } catch (IOException var16) {
            if (var16 instanceof RemoteException) {
                throw (RemoteException)var16;
            }
            throw new ConnectIOException("error during JRMP connection establishment", var16);
        }
    } else {
        try {
            var1 = this.multiplexer.openConnection();
        } catch (IOException var13) {
            synchronized(this) {
                this.usingMultiplexer = false;
                this.multiplexer = null;
            }
            throw new ConnectIOException("error opening virtual connection over multiplexed connection", var13);
        }
    }
    return var1;
}


要点

  • 手写RPC时

    • 序列化的

      • 包名和类名必须一致

时序图

RMI_Service_Invoker.png

来源于: https://javaguide.net

公众号:不止极客


不止极客
9 声望0 粉丝

[链接]