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. 正则爬取豆瓣Top250数据存储到CSV文件(6行代码)

    利用正则爬取豆瓣TOP250电影信息 电影名字 电影年份 电影评分 评论人数 import requests import csv import re # 不算导包的话正式代码6行 存储到csv文件 ...

  2. ArcObjects SDK开发 022 开发框架搭建-FrameWorkUI包设计

    1.CommandUIs部分 这部分主要是定义承载Command和Tool的具体UI.如下图所示. 以CommandUI结尾的这几个类都是继承了Framework.Engine里面的ICommandU ...

  3. [0x11] 131.直方图中最大的矩形【单调栈】

    题意 link(more:SPOJ1805) 如图,在水平线上有 \(n(n\leqslant10^5)\) 个宽度为 1 ,高度为 \(h(0\leqslant h\leqslant10^9)\) ...

  4. 控制台运行java

    控制台执行java 新建java代码 新建一个记事本文件,将文件名改为HelloWorld.java,注意:后缀是.java. 若没有显示文件后缀,可以在资源管理器打开显示后缀,然后再次修改文件名,一 ...

  5. ArcGIS工具 - 按要素裁切数据库

    在GIS处理数据中,经常需要分图,将整个任务区划分成若干块,由不同的人协作完成.为了节省分图裁切时间,减少人员操作失误,为源GIS专门制作了按要素裁切数据库工具,以提高数据生产效率. 需求描述 裁切单 ...

  6. python基础练习题 经常更新

    小练习 1.打印出jason l1 = [11, 22, 'kevin', ['tony', 'jerry', [123, 456, 'jason']]] # print(l1[3][2][2]) l ...

  7. 算法学习笔记(9): 中国剩余定理(CRT)以及其扩展(EXCRT)

    扩展中国剩余定理 讲解扩展之前,我们先叙述一下普通的中国剩余定理 中国剩余定理 中国剩余定理通过一种非常精巧的构造求出了一个可行解 但是毕竟是构造,所以相对较复杂 \[\begin{cases} x ...

  8. 浅谈RMQ问题

    RMQ:question 有一个长度为 N N N的数组,数组中的数是无序的( 1 < = n < = 5 ∗ 1 0 5 1<=n<=5*10^5 1<=n<=5 ...

  9. 跟我学Python丨图像增强及运算:局部直方图均衡化和自动色彩均衡化处理

    摘要:本文主要讲解图像局部直方图均衡化和自动色彩均衡化处理.这些算法可以广泛应用于图像增强.图像去噪.图像去雾等领域. 本文分享自华为云社区<[Python从零到壹] 五十四.图像增强及运算篇之 ...

  10. CDH-hive内进行删除操作

    hive安装后需要修改已建的表及查询操作,在执行修改操作时遇到了如下问题.   hive> update dp set name='beijing' where id=1159; FAILED: ...