//此时通常情况下是使用RMIInvocationWrapper封装的JDK代理类,切面为RemoteInvocationTraceInterceptor
exportedObject = getObjectToExport();
if(logger.isInfoEnabled())
logger.info((new StringBuilder()).append("Binding service '").append(serviceName).append("' to RMI registry: ").append(registry).toString());
//Export RMI object
if(clientSocketFactory != null)
UnicastRemoteObject.exportObject(exportedObject, servicePort, clientSocketFactory, serverSocketFactory);
else
UnicastRemoteObject.exportObject(exportedObject, servicePort);
try
{
if(replaceExistingBinding)
registry.rebind(serviceName, exportedObject);
else
registry.bind(serviceName, exportedObject);
}
catch(AlreadyBoundException ex)
{
unexportObjectSilently();
throw new IllegalStateException((new StringBuilder()).append("Already an RMI object bound for name '").append(serviceName).append("': ").append(ex.toString()).toString());
}
catch(RemoteException ex)
{
unexportObjectSilently();
throw ex;
}
}
之前有提到过,当请求某个RMI服务的时候,RMI会根据注册的服务名称,将请求引导至远程对象处理中,这个处理类便是使用getObjectToExport()进行创建。
protected Remote getObjectToExport()
{
//如果配置的service属性对应的类实现了Remote接口且没有配置serviceEnterface属性
if((getService() instanceof Remote) && (getServiceInterface() == null || java/rmi/Remote.isAssignableFrom(getServiceInterface())))
return (Remote)getService();
if(logger.isDebugEnabled())
//对service进行封装
logger.debug((new StringBuilder()).append("RMI service [").append(getService()).append("] is an RMI invoker").toString());
return new RmiInvocationWrapper(getProxyForService(), this);
}
请求处理类的初始化主要处理规则为:如果配置的service属性对应的类实现了Remote接口且没有配置serviceInterface属性,那么直接使用service作为处理类;否则,使用RMIInvocationWrapper对service的代理类和当前类也就是RMIServiceExporter进行封装。
经过这样的封装,客户端与服务端便可以达成一致协议,当客户端检测到是RMIInvocationWrapper类型stub的时候便会直接调用其invoke方法,使得调用端与服务端很好地连接在了一起。而RMIInvocationWrapper封装了用于处理请求的代理类,在invoke中便会使用代理类进行进一步处理。
之前的逻辑已经非常清楚了,当请求RMI服务时会由注册表Registry实例将请求转向之前注册的处理类去处理,也就是之前封装的RMIInvocationWrapper,然后由RMIInovationWrapper中的invoke方法进行处理,那么为什么不是在invoke方法中直接使用service,而是通过代理在此将service封装呢?
这其中的一个关键点是,在创建代理时添加了一个增强拦截器RemoteInvocationTraceInterceptor,目的是为了对方法调用进行打印跟踪,但是如果直接在invoke方法中硬编码这些日志,会使代码看起来很不优雅,而且耦合度很高,使用代理的方式就会解决这样的问题,而且会有很高的可扩展性。
protected Object getProxyForService()
{
//验证service
checkService();
//验证serviceInterface
checkServiceInterface();
//使用JDK的方式创建代理
ProxyFactory proxyFactory = new ProxyFactory();
//添加代理接口
proxyFactory.addInterface(getServiceInterface());
if(registerTraceInterceptor == null ? interceptors == null : registerTraceInterceptor.booleanValue())
//加入代理的横切面RemoteInvocationTraceInterceptor并记录Exporter名称
proxyFactory.addAdvice(new RemoteInvocationTraceInterceptor(getExporterName()));
if(interceptors != null)
{
AdvisorAdapterRegistry adapterRegistry = GlobalAdvisorAdapterRegistry.getInstance();
for(int i = 0; i < interceptors.length; i++)
proxyFactory.addAdvisor(adapterRegistry.wrap(interceptors[i]));
}
//设置要代理的目标类
proxyFactory.setTarget(getService());
proxyFactory.setOpaque(true);
//创建代理
return proxyFactory.getProxy(getBeanClassLoader());
}
RMI服务激活调用
之前反复提到过,由于在之前bean初始化的时候做了服务名称绑定this.registry.bind(this.serviceName,thhis.exportedObjedt),其中的exportedObject其实是被RMIInvocationWrapper进行封装过的,也就是说当其他服务调用serviceName的RMI服务时,Java会为我们封装其内部操作,而直接会将代码转向RMIInvocationWrapper测invoke方法中。
public Object invoke(RemoteInvocation invocation)
throws RemoteException, NoSuchMethodException, IllegalAccessException, InvocationTargetException
{
return rmiExporter.invoke(invocation, wrappedObject);
}
而此时this.RMIExporter为之前初始化的RMIServiceExporter,invocation为包含着需要激活的方法参数,而wrappedObject则是之前封装的代理类。
protected Object invoke(RemoteInvocation invocation, Object targetObject)
throws NoSuchMethodException, IllegalAccessException, InvocationTargetException
{
return super.invoke(invocation, targetObject);
}
protected Object invoke(RemoteInvocation invocation, Object targetObject)
throws NoSuchMethodException, IllegalAccessException, InvocationTargetException
{
if(logger.isTraceEnabled())
logger.trace((new StringBuilder()).append("Executing ").append(invocation).toString());
try
{
return getRemoteInvocationExecutor().invoke(invocation, targetObject);
}
catch(NoSuchMethodException ex)
{
if(logger.isDebugEnabled())
logger.warn((new StringBuilder()).append("Could not find target method for ").append(invocation).toString(), ex);
throw ex;
}
catch(IllegalAccessException ex)
{
if(logger.isDebugEnabled())
logger.warn((new StringBuilder()).append("Could not access target method for ").append(invocation).toString(), ex);
throw ex;
}
catch(InvocationTargetException ex)
{
if(logger.isDebugEnabled())
logger.debug((new StringBuilder()).append("Target method failed for ").append(invocation).toString(), ex.getTargetException());
throw ex;
}
}
public Object invoke(RemoteInvocation invocation, Object targetObject)
throws NoSuchMethodException, IllegalAccessException, InvocationTargetException
{
Assert.notNull(invocation, "RemoteInvocation must not be null");
Assert.notNull(targetObject, "Target object must not be null");
//通过反射方式激活方法
return invocation.invoke(targetObject);
}
<pre name="code" class="java">public Object invoke(Object targetObject)
throws NoSuchMethodException, IllegalAccessException, InvocationTargetException
{
//根据方法名称获取代理中的方法
Method method = targetObject.getClass().getMethod(methodName, parameterTypes);
//执行代理中方法
return method.invoke(targetObject, arguments);
}
targetObject为之前封装的代理类。