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. 现代 CSS 高阶技巧,完美的波浪进度条效果!

    本文是 CSS Houdini 之 CSS Painting API 系列第三篇. 现代 CSS 之高阶图片渐隐消失术 现代 CSS 高阶技巧,像 Canvas 一样自由绘图构建样式! 在上两篇中,我 ...

  2. Linux 下使用Docker 安装 LNMP环境 超详细

    首先在阿里云购买了一台服务器 选择了华南-深圳地区 操作系统选用了 CentOS8.0 64位 1. 初始化账号密码 登陆xshell,开始装Docker 一.安装docker 1.Docker 要求 ...

  3. 组策略编辑器(gpedit.msc)找不到文件解决方法

    打开[此电脑]中的C盘,依次打开Windows-system32-gpedit.msc,或者输入:C:\Windows\System32\gpedit.msc,查看是否存在gpedit.msc文件(没 ...

  4. python 之列表(list)处理

    列表(list) 创建一个列表,只要把逗号分隔的不同的数据项使用方括号括起来即可,一个列表中的数据类型可以各不相同,可以同时分别为整数.实数.字符串等基本类型,甚至是列表.元组.字典.集合以及其他自定 ...

  5. 手写promise解决回调地狱问题

    在介绍promise之前我们先来看一段代码: 根据案例我们可以看出,这段代码可以无限的嵌套下去,但是每嵌套一层,代码的运行就会降低,而解决回调地狱最好的办法就是new promise 一.什么是 pr ...

  6. day01-ES6新特性

    ES6新特性 1.ES6是什么? DCMAScript 6.0(以下简称ES6)是JavaScript语言的下一代标准,2015年6月发布 ES6设计目标:达到JavaScript语言可以用来编写复杂 ...

  7. C语言常用知识总结

    在 C 语言中,常量是一种固定值的标识符,它的值在程序执行期间不会改变. C 语言中有几种不同类型的常量: 字符常量:用单引号括起来的单个字符,例如 'A'.'b'.'1' 等. 字符串常量:用双引号 ...

  8. CVE-2007-4556 s2-001

    漏洞名称 S2-001 远程代码执行 利用条件 WebWork 2.1 (with altSyntax enabled), WebWork 2.2.0 - WebWork 2.2.5, Struts ...

  9. Redis 数据结构-双向链表

    Redis 数据结构-双向链表 最是人间留不住,朱颜辞镜花辞树. 1.简介 Redis 之所以快主要得益于它的数据结构.操作内存数据库.单线程和多路 I/O 复用模型,进一步窥探下它常见的五种基本数据 ...

  10. 如何通过Terraform Associate考试并获得证书

    1 什么是Terraform? Terraform是一个IaC工具,IaC全称为Infrastructure as Code,基础设施即代码.它的理念是通过代码来管理基础设施,如服务器.数据库等,更多 ...