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. Blazor组件自做十二 : Blazor Pdf Reader PDF阅读器 组件 (新版 7.1 移除pdfobject)

    Blazor Pdf Reader PDF阅读器 组件 示例: https://www.blazor.zone/PdfReaders https://blazor.app1.es/pdfReaders ...

  2. echarts柱状图渐变色并且显示数据及柱状图的宽度调整

    series: [{ type: 'bar', name: '起飞', barWidth: '20px', //柱状图的宽度 itemStyle: { normal: { //显示渐变色颜色 colo ...

  3. vscode问题:由于找不到ffmpag.dll文件,无法继续执行代码

    工作中发现VS code打不开了,显示如下:  解决方法: 一.打开Microsoft VS Code 文件夹,发现一部分文件被打包进了一个叫"_"的文件夹(第一个)  二.把该文 ...

  4. [数据结构]单向链表及其基本操作(C语言)

    单向链表 什么是单向链表 链表是一种物理储存单元上非连续.非顺序的储存结构.它由一系列结点(链表中每一个元素称为结点)组成,结点可动态生成.每个结点包括两个部分:一个是存储数据元素的数据域,另一个是存 ...

  5. 9、手写一个starter

    一.starte详解: 1.starter场景启动器: SpringBoot-starter是一个集成接合器,主要完成两件事: (1).引入模块所需的相关jar包 (2).自动配置各自模块所需的属性 ...

  6. Vue前后端分离实现登录的一个简单demo

    1.建立一个Maven项目,并添加Spring相关依赖 2.编写Controller类相应的接口和配置类 LoginController类,编写接口的业务逻辑 package com.springbo ...

  7. python模块(module)

    目录 模块化(module)程序设计理念 模块和包概念的进化史 标准库模块(standard library) 为什么需要模块化编程 模块化编程的流 模块的 API 和功能描述要点 模块的创建和测试代 ...

  8. C++ 之 cout 格式化输出

    写代码时每次用到格式化输出就各种搜来搜去,今天好好整理一下,方便以后查阅和使用. 参考链接: C++ 之 cout 使用攻略 C++ 格式化输出 首先,加上头文件 #include <ioman ...

  9. [cocos2d-x]关于Action

    Action的分类 第一种:FiniteTimeAction类:有限时间的动作类 第二种:Follow类:节点跟随另一种节点的类 第三种:Speed类:节点执行速度类 第一种有限时间的动作类又分为瞬时 ...

  10. Java学习笔记:2022年1月7日

    Java学习笔记:2022年1月7日 摘要:今天的这篇笔记主要是通过讲解基本的JVM结构来理解Java中一些行为的运行机制,进而更加的深入理解Java的运行原理. 目录 Java学习笔记:2022年1 ...