死磕rmi之 RegistryImpl

Registry初始化

可以把注册中心理解为特殊的远程对象,这个对象就像一个容器一样,存储其他远程对象。

可以本地直接调用四大方法,也可通过调用远程对象的方式调用。

查看一下类继承关系

可参照https://android.googlesource.com/toolchain/gcc.git/+/eclair/gcc-4.2.1/libjava/classpath/gnu/java/rmi

public class RegistryImpl extends RemoteServer implements Registry
public abstract class RemoteServer extends RemoteObject
public abstract class RemoteObject implements Remote, java.io.Serializable {

java.rmi.registry.LocateRegistry#createRegistry(int)

创建并暴露一个Registry在localhost上,接受特定的请求

/**
 * Creates and exports a <code>Registry</code> instance on the local
 * host that accepts requests on the specified <code>port</code>.
 *
 * <p>The <code>Registry</code> instance is exported as if the static
 * {@link UnicastRemoteObject#exportObject(Remote,int)
 * UnicastRemoteObject.exportObject} method is invoked, passing the
 * <code>Registry</code> instance and the specified <code>port</code> as
 * arguments, except that the <code>Registry</code> instance is
 * exported with a well-known object identifier, an {@link ObjID}
 * instance constructed with the value {@link ObjID#REGISTRY_ID}.
 *
 * @param port the port on which the registry accepts requests
 * @return the registry
 * @exception RemoteException if the registry could not be exported
 * @since JDK1.1
 **/
public static Registry createRegistry(int port) throws RemoteException {
    return new RegistryImpl(port);
}

sun.rmi.registry.RegistryImpl#RegistryImpl(int)

public RegistryImpl(final int var1) throws RemoteException {
    this.bindings = new Hashtable(101);
    if (var1 == 1099 && System.getSecurityManager() != null) {
        try {
            AccessController.doPrivileged(new PrivilegedExceptionAction<Void>() {
                public Void run() throws RemoteException {
                    LiveRef var1x = new LiveRef(RegistryImpl.id, var1);
                    //这种写法跟后面的lambda方法不一致啊
                    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 {
    //var1为port
    //liveRef,实时引用,包含,endpoint,id,channel。
    //endpoint的构造在远程对象里已经讲过了。就是通过host+ip,确定一个。在这期间会采集一些host的变化。如果已经存在了,就看host变没变。
    //id为new ObjID(0),RegistryImpl的ID是固定的
        LiveRef var2 = new LiveRef(id, var1);
        //这里为lambda方法
        //下面查看setup方法,也是ref=serverref,然后发布一个对象。把这个对象作为注册中心
        this.setup(new UnicastServerRef(var2, RegistryImpl::registryFilter));
    }

}

sun.rmi.server.UnicastServerRef#UnicastServerRef(sun.rmi.transport.LiveRef, sun.misc.ObjectInputFilter)

public UnicastServerRef(LiveRef var1, ObjectInputFilter var2) {
    super(var1);
    //这里为forceStubUse=false
    this.forceStubUse = false;
    this.hashToMethod_Map = null;
    this.methodCallIDCount = new AtomicInteger(0);
    //远程对象的ServerRef为null,这里有过滤拦截
    this.filter = var2;
}

sun.rmi.registry.RegistryImpl#registryFilter

filter配置参考:https://docs.oracle.com/en/java/javase/11/core/serialization-filtering1.html#GUID-0A1D23AB-2F18-4979-9288-9CFEC04F207E

private static ObjectInputFilter.Status registryFilter(ObjectInputFilter.FilterInfo var0) {
//registryFilter被初始化为sun.rmi.registry.registryFilter
//配置参考
    if (registryFilter != null) {
        ObjectInputFilter.Status var1 = registryFilter.checkInput(var0);
        if (var1 != Status.UNDECIDED) {
            return var1;
        }
    }

    if (var0.depth() > 20L) {
        return Status.REJECTED;
    } else {
        Class var2 = var0.serialClass();
        if (var2 != null) {
            if (!var2.isArray()) {
                return String.class != var2 && !Number.class.isAssignableFrom(var2) && !Remote.class.isAssignableFrom(var2) && !Proxy.class.isAssignableFrom(var2) && !UnicastRef.class.isAssignableFrom(var2) && !RMIClientSocketFactory.class.isAssignableFrom(var2) && !RMIServerSocketFactory.class.isAssignableFrom(var2) && !ActivationID.class.isAssignableFrom(var2) && !UID.class.isAssignableFrom(var2) ? Status.REJECTED : Status.ALLOWED;
            } else {
                return var0.arrayLength() >= 0L && var0.arrayLength() > 1000000L ? Status.REJECTED : Status.UNDECIDED;
            }
        } else {
            return Status.UNDECIDED;
        }
    }
}

sun.rmi.registry.RegistryImpl#setup

private void setup(UnicastServerRef var1) throws RemoteException {
    this.ref = var1;
    //true 要这个类为永久类
    //之后的逻辑跟暴露远程对象一样了
    var1.exportObject(this, (Object)null, true);
}

sun.rmi.server.UnicastServerRef#exportObject(java.rmi.Remote, java.lang.Object, boolean)

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) {
    //设置注册中心为var1,就是它自己。
        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;
}

sun.rmi.server.Util#createProxy

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());
    }
//这里为true
//sun.rmi.registry.RegistryImpl_Stub 应该是用RegistryImpl的类加载器加载的,跟普通远程对象不是一个类加载器,所以,普通远程对象这里返回false。
//验证一下这个猜测
//RegistryImpl的类加载器为null,也是BootstrapClassloader。这个是用c++写的,用来加载系统类。通过包名可得,RegistryImpl_Stub为系统类。
//普通远程对象的类加载器为AppClassLoaer
    if (var2 || !ignoreStubClasses && stubClassExists(var3)) {
        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);
        }
    }
}

处理逻辑

sun.rmi.transport.LiveRef#exportObject

sun.rmi.transport.tcp.TCPEndpoint#exportObject

sun.rmi.transport.tcp.TCPTransport#exportObject

sun.rmi.transport.tcp.TCPTransport#listen

sun.rmi.transport.Transport#exportObject

sun.rmi.server.UnicastServerRef#dispatch

这里有一个分支跟普通远程对象不一样。

public void dispatch(Remote var1, RemoteCall var2) throws IOException {
    try {
        int var3;
        ObjectInput var41;
        try {
            var41 = var2.getInputStream();
            //读4个字节
            var3 = var41.readInt();
        } catch (Exception var38) {
            throw new UnmarshalException("error unmarshalling call header", var38);
        }
//这里registryImpl可以进入,普通对象不行。
        if (this.skel != null) {
            this.oldDispatch(var1, var2, var3);
            return;
        }

        if (var3 >= 0) {
            throw new UnmarshalException("skeleton class not found but required for client version");
        }

        long var4;
        try {
            var4 = var41.readLong();
        } catch (Exception var37) {
            throw new UnmarshalException("error unmarshalling call header", var37);
        }

        MarshalInputStream var7 = (MarshalInputStream)var41;
        var7.skipDefaultResolveClass();
        Method var42 = (Method)this.hashToMethod_Map.get(var4);
        if (var42 == null) {
            throw new UnmarshalException("unrecognized method hash: method not supported by remote object");
        }

        this.logCall(var1, var42);
        Object[] var9 = null;

        try {
            this.unmarshalCustomCallData(var41);
            var9 = this.unmarshalParameters(var1, var42, var7);
        } catch (AccessException var34) {
            ((StreamRemoteCall)var2).discardPendingRefs();
            throw var34;
        } catch (ClassNotFoundException | IOException var35) {
            ((StreamRemoteCall)var2).discardPendingRefs();
            throw new UnmarshalException("error unmarshalling arguments", var35);
        } finally {
            var2.releaseInputStream();
        }

        Object var10;
        try {
            var10 = var42.invoke(var1, var9);
        } catch (InvocationTargetException var33) {
            throw var33.getTargetException();
        }

        try {
            ObjectOutput var11 = var2.getResultStream(true);
            Class var12 = var42.getReturnType();
            if (var12 != Void.TYPE) {
                marshalValue(var12, var10, var11);
            }
        } catch (IOException var32) {
            throw new MarshalException("error marshalling return", var32);
        }
    } catch (Throwable var39) {
        Object var6 = var39;
        this.logCallException(var39);
        ObjectOutput var8 = var2.getResultStream(false);
        if (var39 instanceof Error) {
            var6 = new ServerError("Error occurred in server thread", (Error)var39);
        } else if (var39 instanceof RemoteException) {
            var6 = new ServerException("RemoteException occurred in server thread", (Exception)var39);
        }

        if (suppressStackTraces) {
            clearStackTraces((Throwable)var6);
        }

        var8.writeObject(var6);
        if (var39 instanceof AccessException) {
            throw new IOException("Connection is not reusable", var39);
        }
    } finally {
        var2.releaseInputStream();
        var2.releaseOutputStream();
    }

}

sun.rmi.server.UnicastServerRef#oldDispatch

private void oldDispatch(Remote var1, RemoteCall var2, int var3) throws Exception {
    ObjectInput var6 = var2.getInputStream();

    try {
        Class var7 = Class.forName("sun.rmi.transport.DGCImpl_Skel");
        if (var7.isAssignableFrom(this.skel.getClass())) {
            ((MarshalInputStream)var6).useCodebaseOnly();
        }
    } catch (ClassNotFoundException var9) {
    }

    long var4;
    try {
    //读8个字节
        var4 = var6.readLong();
    } catch (Exception var8) {
        throw new UnmarshalException("error unmarshalling call header", var8);
    }
//允许的方法,四种,写死。
    Operation[] var10 = this.skel.getOperations();
    this.logCall(var1, var3 >= 0 && var3 < var10.length ? var10[var3] : "op: " + var3);
    //这里会设置UnicastServerRef.this.filter,就是上文的RegistryImpl::registryFilter 到输入流var6上。
    this.unmarshalCustomCallData(var6);
    //这里是逻辑
    //var1就是注册中心
    //var2就remotecall,持有socket的输入输出流
    //var3为输入流读入的4字节int,opnum
	//var4为输入流读入的8字节long,hash
    this.skel.dispatch(var1, var2, var3, var4);
}

sun.rmi.registry.RegistryImpl_Skel#dispatch

这个是提供给远程调用用的

public void dispatch(Remote var1, RemoteCall var2, int var3, long var4) throws Exception {
    if (var3 < 0) {
    //这些是hash值
        if (var4 == 7583982177005850366L) {
            var3 = 0;
        } else if (var4 == 2571371476350237748L) {
            var3 = 1;
        } else if (var4 == -7538657168040752697L) {
            var3 = 2;
        } else if (var4 == -8381844669958460146L) {
            var3 = 3;
        } else {
            if (var4 != 7305022919901907578L) {
                throw new UnmarshalException("invalid method hash");
            }

            var3 = 4;
        }
    } else if (var4 != 4905912898345647071L) {
        throw new SkeletonMismatchException("interface hash mismatch");
    }

    RegistryImpl var6 = (RegistryImpl)var1;
    StreamRemoteCall var7 = (StreamRemoteCall)var2;
    String var8;
    ObjectInputStream var9;
    ObjectInputStream var10;
    Remote var81;
    switch (var3) {
        case 0:
            RegistryImpl.checkAccess("Registry.bind");

            try {
                var10 = (ObjectInputStream)var7.getInputStream();
                //读取name
                //会调用java.io.ObjectInputStream#readObject(java.lang.Class<?>)
                var8 = SharedSecrets.getJavaObjectInputStreamReadString().readString(var10);
                //反序列化对象
                var81 = (Remote)var10.readObject();
            } catch (IOException | ClassNotFoundException | ClassCastException var78) {
                var7.discardPendingRefs();
                throw new UnmarshalException("error unmarshalling arguments", var78);
            } finally {
                var7.releaseInputStream();
            }

            var6.bind(var8, var81);

            try {
                var7.getResultStream(true);
                break;
            } catch (IOException var77) {
                throw new MarshalException("error marshalling return", var77);
            }
        case 1:
            var7.releaseInputStream();
            String[] var80 = var6.list();

            try {
                ObjectOutput var82 = var7.getResultStream(true);
                var82.writeObject(var80);
                break;
            } catch (IOException var76) {
                throw new MarshalException("error marshalling return", var76);
            }
        case 2:
            try {
                var9 = (ObjectInputStream)var7.getInputStream();
                var8 = SharedSecrets.getJavaObjectInputStreamReadString().readString(var9);
            } catch (IOException | ClassCastException var74) {
                var7.discardPendingRefs();
                throw new UnmarshalException("error unmarshalling arguments", var74);
            } finally {
                var7.releaseInputStream();
            }

            var81 = var6.lookup(var8);

            try {
                ObjectOutput var83 = var7.getResultStream(true);
                var83.writeObject(var81);
                break;
            } catch (IOException var73) {
                throw new MarshalException("error marshalling return", var73);
            }
        case 3:
            RegistryImpl.checkAccess("Registry.rebind");

            try {
                var10 = (ObjectInputStream)var7.getInputStream();
                var8 = SharedSecrets.getJavaObjectInputStreamReadString().readString(var10);
                var81 = (Remote)var10.readObject();
            } catch (IOException | ClassNotFoundException | ClassCastException var71) {
                var7.discardPendingRefs();
                throw new UnmarshalException("error unmarshalling arguments", var71);
            } finally {
                var7.releaseInputStream();
            }

            var6.rebind(var8, var81);

            try {
                var7.getResultStream(true);
                break;
            } catch (IOException var70) {
                throw new MarshalException("error marshalling return", var70);
            }
        case 4:
            RegistryImpl.checkAccess("Registry.unbind");

            try {
                var9 = (ObjectInputStream)var7.getInputStream();
                var8 = SharedSecrets.getJavaObjectInputStreamReadString().readString(var9);
            } catch (IOException | ClassCastException var68) {
                var7.discardPendingRefs();
                throw new UnmarshalException("error unmarshalling arguments", var68);
            } finally {
                var7.releaseInputStream();
            }

            var6.unbind(var8);

            try {
                var7.getResultStream(true);
                break;
            } catch (IOException var67) {
                throw new MarshalException("error marshalling return", var67);
            }
        default:
            throw new UnmarshalException("invalid method number");
    }

}

稍微看一下readString方法。感觉写的也是很杂糅,将TC_STRING与TC_LONGSTRING的逻辑混在一起了。

java.io.ObjectInputStream#readString(boolean)

/**
 * Reads in and returns new string.  Sets passHandle to new string's
 * assigned handle.
 */
private String readString(boolean unshared) throws IOException {
    String str;
    byte tc = bin.readByte();
    switch (tc) {
        case TC_STRING:
            str = bin.readUTF();
            break;

        case TC_LONGSTRING:
            str = bin.readLongUTF();
            break;

        default:
            throw new StreamCorruptedException(
                String.format("invalid type code: %02X", tc));
    }
    passHandle = handles.assign(unshared ? unsharedMarker : str);
    handles.finish(passHandle);
    return str;
}

总结

1、registryImpl有两种注册方式,本地注册,远程注册。

2、远程注册,就跟调用远程对象一样

posted @ 2023-01-13 10:00  wqkant  阅读(33)  评论(0编辑  收藏  举报