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. uniapp微信小程序返回上一页并刷新数据

    根据要求:详情页返回列表页时,要刷新列表页的数据,操作如下 @click="goBack" goBack{ let pages = getCurrentPages(); // 当前 ...

  2. Linux命令篇 - nc(ncat) 命令

    nc (ncat) Ncat is a feature-packed networking utility which reads and writes data across networks fr ...

  3. [OpenCV实战]52 在OpenCV中使用颜色直方图

    颜色直方图是一种常见的图像特征,顾名思义颜色直方图就是用来反映图像颜色组成分布的直方图.颜色直方图的横轴表示像素值或像素值范围,纵轴表示该像素值范围内像素点的个数或出现频率.颜色直方图属于计算机视觉中 ...

  4. Java学习记录:2022年1月13日(其二)

    Java学习记录:2022年1月13日(其二) ​ 摘要:本篇笔记主要记录了在设计类时的一些注意事项,类加载时类中各个部分的加载顺序以及继承和多态的知识. 目录 Java学习记录:2022年1月13日 ...

  5. pymysql在读取bit类型时显示x00的解决办法

    #用于转换bit在pymysql中显示为x00的问题from pymysql import convertersconverions = converters.conversionsconverion ...

  6. Collection集合常用功能-Iterator接口介绍

    Collection集合常用功能 Collection是所有单列集合的父接口,因此在Collection中定义了单列集合(List和Set)通用的一些方法,这些方法可用于操作所有的单列集合.方法如下︰ ...

  7. Grafana 系列文章(十一):Loki 中的标签如何使日志查询更快更方便

    ️URL: https://grafana.com/blog/2020/04/21/how-labels-in-loki-can-make-log-queries-faster-and-easier/ ...

  8. 11月17日内容总结——黏包现象、struct模块和解决黏包问题的流程、UDP协议、并发编程理论、多道程序设计技术及进程理论

    目录 一.黏包现象 什么是黏包 黏包现象产生的原因 二.struct模块及解决黏包问题的流程 struct模块 解决黏包问题初级版本 解决过程中遇到的问题 解决黏包问题终极解决方案 三.粘包代码实战 ...

  9. TCP与UDP、socket模块

    1.传输层之TCP与UDP协议 1.TCP协议 1.传输控制协议(也称为TCP协议或可靠协议)是为了在不可靠的互联网络上提供可靠的端到端字节流而专门设计的一个传输协议,(数据不容易丢失);造成数据不容 ...

  10. HTTPS基础原理和配置 - 1

    近期又碰到了SSL相关的事情, 就心血来潮开个新专题 - <HTTPS基础原理和配置> 本文是第一篇文章, 主要介绍SSL TLS加密协议的相关内容. 加密协议历史概要 SSL TLS加密 ...