接上:http://guojuanjun.blog.51cto.com/277646/1423392
这一次我们从学习RegistryImpl_Stub.java和RegistryImpl_Skel.java的实现上学习远程方法的调用过程。
RegistryImpl_Stub.bind:
public void bind(java.lang.String $param_String_1, java.rmi.Remote $param_Remote_2)
throws java.rmi.AccessException, java.rmi.AlreadyBoundException, java.rmi.RemoteException
{
try {
if (useNewInvoke) {
ref.invoke(this, $method_bind_0, new java.lang.Object[] {$param_String_1, $param_Remote_2}, 7583982177005850366L);
} else {
java.rmi.server.RemoteCall call = ref.newCall((java.rmi.server.RemoteObject) this, operations, 0, interfaceHash);
try {
java.io.ObjectOutput out = call.getOutputStream();
out.writeObject($param_String_1);
out.writeObject($param_Remote_2);
} catch (java.io.IOException e) {
throw new java.rmi.MarshalException("error marshalling arguments", e);
}
ref.invoke(call);
ref.done(call);
}
} catch (java.lang.RuntimeException e) {
throw e;
} catch (java.rmi.RemoteException e) {
throw e;
} catch (java.rmi.AlreadyBoundException e) {
throw e;
} catch (java.lang.Exception e) {
throw new java.rmi.UnexpectedException("undeclared checked exception", e);
}
}
public StreamRemoteCall(Connection c, ObjID id, int op, long hash)
throws RemoteException
{
try {
conn = c;
Transport.transportLog.log(Log.VERBOSE,
"write remote call header...");
// write out remote call header info...
// call header, part 1 (read by Transport)
conn.getOutputStream().write(TransportConstants.Call);
getOutputStream(); // creates a MarshalOutputStream
id.write(out); // object id (target of call)
// call header, part 2 (read by Dispatcher)
out.writeInt(op); // method number (operation index)
out.writeLong(hash); // stub/skeleton hash
} catch (IOException e) {
throw new MarshalException("Error marshaling call header", e);
}
}
只要传入对象ID,操作号,接口hash值,就可以定位到远程对象及其方法上。
再看服务端:
public boolean serviceCall(final RemoteCall call) {
try {
final Remote impl;
ObjID id;
try {
id = ObjID.read(call.getInputStream());
} catch (java.io.IOException e) {
throw new MarshalException("unable to read objID", e);
}
/* get the remote object */
Transport transport = id.equals(dgcID) ? null : this;
Target target =
ObjectTable.getTarget(new ObjectEndpoint(id, transport));
if (target == null || (impl = target.getImpl()) == null) {
throw new NoSuchObjectException("no such object in table");
}
final Dispatcher disp = target.getDispatcher();
target.incrementCallCount();
try {
/* call the dispatcher */
transportLog.log(Log.VERBOSE, "call dispatcher");
final AccessControlContext acc =
target.getAccessControlContext();
ClassLoader ccl = target.getContextClassLoader();
Thread t = Thread.currentThread();
ClassLoader savedCcl = t.getContextClassLoader();
try {
t.setContextClassLoader(ccl);
currentTransport.set(this);
try {
java.security.AccessController.doPrivileged(
new java.security.PrivilegedExceptionAction<Void>() {
public Void run() throws IOException {
checkAcceptPermission(acc);
disp.dispatch(impl, call);
return null;
}
}, acc);
} catch (java.security.PrivilegedActionException pae) {
throw (IOException) pae.getException();
}
} finally {
t.setContextClassLoader(savedCcl);
currentTransport.set(null);
}
} catch (IOException ex) {
transportLog.log(Log.BRIEF,
"exception thrown by dispatcher: ", ex);
return false;
} finally {
target.decrementCallCount();
}
} catch (RemoteException e) {
// if calls are being logged, write out exception
if (UnicastServerRef.callLog.isLoggable(Log.BRIEF)) {
// include client host name if possible
String clientHost = "";
try {
clientHost = "[" +
RemoteServer.getClientHost() + "] ";
} catch (ServerNotActiveException ex) {
}
String message = clientHost + "exception: ";
UnicastServerRef.callLog.log(Log.BRIEF, message, e);
}
/* We will get a RemoteException if either a) the objID is
* not readable, b) the target is not in the object table, or
* c) the object is in the midst of being unexported (note:
* NoSuchObjectException is thrown by the incrementCallCount
* method if the object is being unexported). Here it is
* relatively safe to marshal an exception to the client
* since the client will not have seen a return value yet.
*/
try {
ObjectOutput out = call.getResultStream(false);
UnicastServerRef.clearStackTraces(e);
out.writeObject(e);
call.releaseOutputStream();
} catch (IOException ie) {
transportLog.log(Log.BRIEF,
"exception thrown marshalling exception: ", ie);
return false;
}
}
return true;
}
id = ObjID.read(call.getInputStream());
读到ObjId.
Target target =
ObjectTable.getTarget(new ObjectEndpoint(id, transport));
impl = target.getImpl()
从对象表中找到远程对象的target对象,并获取远程对象。
disp.dispatch(impl, call);
分发调用到远程对象上。
RegistryImpl的远程调用是这样实现,但普通对象在JDK1.5之后,已没有显示的stub类.而是用一个代理类代替存根对象,具体参考:http://guojuanjun.blog.51cto.com/277646/1350826