在服务器端,我有一个ListenerManager,它会向其Listener发出回调.使用Spring RmiServiceExporter导出管理器
在客户端,我有一个由RmiProxyFactoryBean创建的管理器的代理,以及通过此代理向服务器端的管理器注册的Listener实现.
到目前为止一直很好:ListenerManager被赋予一个Listener并且它调用它的回调,但是由于监听器只是客户端对象的反序列化副本,所以回调运行在服务器端而不是客户端.
如何让Spring在服务器端生成代理到客户端侦听器,以便服务器调用的回调在客户端远程执行?当然,我不需要另一个(出口商,代理工厂)对相反的方向?
解决方法:
纯RMI解决方案:客户端侦听器对象需要实现java.rmi.server.UnicastRemoteObject.如果是这样,并且它的每个方法抛出RemoteException,那么当它通过管理器代理传递给服务器时,一切都自动连接,服务器端代理到该侦听器的方法调用是对真实客户端上的方法的远程调用对象.
这样做,但是能够在不需要特定超类的情况下包装对象以进行导出更好.我们可以使用CGLIB Enhancer将侦听器“代理”为同时实现服务接口的UnicastRemoteObject的子类.这仍然要求目标对象实现java.rmi.Remote并声明抛出RemoteException.
下一步是一个解决方案,可以导出任意对象以远程调用其方法,而无需实现Remote或声明抛出RemoteException.我们必须将这个代理与现有的Spring基础结构集成在一起,我们可以使用RmiBasedExporter的新实现来模拟RmiServiceExporter#prepare()的非注册表位,以导出代理的RMI存根和RmiClientInterceptor的调用部分. doInvoke(MethodInvocation,RmiInvocationHandler).我们需要能够获得服务接口的导出代理实例.我们可以使用Spring对显然“导出”非RMI接口的方法对此进行建模. Spring代理接口以生成用于调用非RMI方法的RmiInvocationWrapper,序列化方法细节和参数,然后在RMI连接的远端调用它.
>使用ProxyFactory和RmiInvocationHandler实现来代理目标对象.
>使用RmiBasedExporter的新实现来getObjectToExport(),并使用UnicastRemoteObject #export(obj,0)将其导出.
>对于调用处理程序,rmiInvocationHandler.invoke(invocationFactory.createRemoteInvocation(invocation)),带有DefaultRemoteInvocationFactory.
>处理异常并适当地换行以避免看到UndeclaredThrowableExceptions.
因此,我们可以使用RMI导出任意对象.这意味着我们可以在客户端使用其中一个对象作为RMI服务器端对象上的RMI方法调用的参数,并且当服务器端的反序列化存根调用了方法时,这些方法将在客户端.魔法.