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、远程注册,就跟调用远程对象一样

死磕rmi之 RegistryImpl的更多相关文章

  1. mysql每秒最多能插入多少条数据 ? 死磕性能压测

    前段时间搞优化,最后瓶颈发现都在数据库单点上. 问DBA,给我的写入答案是在1W(机械硬盘)左右. 联想起前几天infoQ上一篇文章说他们最好的硬件写入速度在2W后也无法提高(SSD硬盘) 但这东西感 ...

  2. 【死磕Java并发】-----Java内存模型之happend-before

    在上篇博客([死磕Java并发]-–深入分析volatile的实现原理)LZ提到过由于存在线程本地内存和主内存的原因,再加上重排序,会导致多线程环境下存在可见性的问题.那么我们正确使用同步.锁的情况下 ...

  3. 死磕 java集合之DelayQueue源码分析

    问题 (1)DelayQueue是阻塞队列吗? (2)DelayQueue的实现方式? (3)DelayQueue主要用于什么场景? 简介 DelayQueue是java并发包下的延时阻塞队列,常用于 ...

  4. 死磕 java集合之PriorityBlockingQueue源码分析

    问题 (1)PriorityBlockingQueue的实现方式? (2)PriorityBlockingQueue是否需要扩容? (3)PriorityBlockingQueue是怎么控制并发安全的 ...

  5. 死磕 java集合之PriorityQueue源码分析

    问题 (1)什么是优先级队列? (2)怎么实现一个优先级队列? (3)PriorityQueue是线程安全的吗? (4)PriorityQueue就有序的吗? 简介 优先级队列,是0个或多个元素的集合 ...

  6. 【死磕 Spring】----- IOC 之解析 bean 标签:开启解析进程

    原文出自:http://cmsblogs.com import 标签解析完毕了,再看 Spring 中最复杂也是最重要的标签 bean 标签的解析过程. 在方法 parseDefaultElement ...

  7. 【死磕 Spring】—– IOC 之解析Bean:解析 import 标签

    原文出自:http://cmsblogs.com 在博客[死磕Spring]----- IOC 之 注册 BeanDefinition中分析到,Spring 中有两种解析 Bean 的方式.如果根节点 ...

  8. 【死磕 Spring】----- IOC 之 获取 Document 对象

    原文出自:http://cmsblogs.com 在 XmlBeanDefinitionReader.doLoadDocument() 方法中做了两件事情,一是调用 getValidationMode ...

  9. 【死磕 Spring】----- IOC 之 获取验证模型

    原文出自:http://cmsblogs.com 在上篇博客[死磕Spring]----- IOC 之 加载 Bean 中提到,在核心逻辑方法 doLoadBeanDefinitions()中主要是做 ...

  10. 【死磕 Spring】----- IOC 之 加载 Bean

    原文出自:http://cmsblogs.com 先看一段熟悉的代码: ClassPathResource resource = new ClassPathResource("bean.xm ...

随机推荐

  1. Kubernetes环境鉴权与自动发现

    概览文章中提到了k8s的鉴权模式,简单回顾下: RBAC: Role-based access control 是基于角色的访问控制 ABAC: Atrribute-based access cont ...

  2. python 错误之TypeError: XXXXX() takes no keyword arguments

    举个例子: str1 = 'sunlightn' f = str1.rfind("n", __start=1, __end=2) print(f) 以上代码运行后出现: " ...

  3. 计算存储分离在京东云消息中间件JCQ上的应用

    作者:田寄远 JCQ 全名 JD Cloud Message Queue,是京东云自研.具有 CloudNative 特性的分布式消息中间件. JCQ 设计初衷即为适应云特性的消息中间件:具有高可用. ...

  4. 历时9个月重构iNeuOS工业互联网操作系统,打造工业领域的“Office”

    目       录 1.      概述... 1 2.      整体介绍... 2 3.      主要功能简介... 5 1.   概述 历时9个月的时间,对iNeuOS工业互联网操作系统进行全 ...

  5. JavaScript:操作符:逗号运算符

    逗号运算符,是极少见的运算符,我们看一下代码理解一下逗号运算符的功能: 先说结论,逗号运算符的优先级非常低,比赋值运算符=还要低: 同时,逗号隔开的几个表达式,都会各自进行计算,但是整体表达式只会返回 ...

  6. 【转载】SQL SERVER 通过对汉字、字母和数字的Unicode码区间的判断来识别字符串

    A~Z :65~90 a~z :97~122 0-9 : 48-57   –汉字unicode编码范围:[0x4e00,0x9fa5](或十进制[19968,40869])   SELECT * FR ...

  7. Java基础篇——IO流

    流 内存和存储设备之间传输数据的通道 流的分类 按方向划分 输入流(读):存储设备→内存 输出流(写):内存→存储设备 按单位划分. 字节流:以字节为单位,可以读写所有数据 字符流:以字符为单位,只能 ...

  8. [WPF]数据绑定Demo

    目录 1.View模型代码 2.ViewModel模型代码 3.数据模型 4.样例演示 5.一些知识点 这里简单实现一个listbox绑定的功能,符合MVVM模型. View模型代码(View视图以及 ...

  9. C++ 一种交换两个数的思路

    在 Lua 或者 Python 中可以使用多值赋值语句来交换两个数.例如:a, b = b, a.在 C++ 中有没有类似的操作? 先解析一下多值赋值的原理,a, b = b, a 等价于 t1, t ...

  10. 一类(One-Class)分类器

    本文摘自博客和论文,参考文献请看文末. 一类分类技术概念 与传统的分类技术不同,一类分类技术仅采用隶属于一个类别的样本来训练分类器,其通常被用于某种极端场景,即训练样本仅包含正常样本,而异常样本不可得 ...