Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/329.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 在客户端执行来自服务器的spring双向rmi回调_Java_Spring_Proxy_Callback_Rmi - Fatal编程技术网

Java 在客户端执行来自服务器的spring双向rmi回调

Java 在客户端执行来自服务器的spring双向rmi回调,java,spring,proxy,callback,rmi,Java,Spring,Proxy,Callback,Rmi,在服务器端,我有一个ListenerManager,它向它的监听器发出回调。使用SpringRmiServiceExporter导出管理器 在客户端,我有一个由RmiProxyFactoryBean创建的管理器代理,以及一个通过该代理向服务器端的管理器注册的Listener实现 到目前为止还不错:ListenerManager有一个Listener,它调用它的回调,但是由于侦听器只是客户端对象的反序列化副本,回调在服务器端运行,而不是客户端 如何让Spring在服务器端为客户端侦听器生成一个代理

在服务器端,我有一个
ListenerManager
,它向它的
监听器发出回调。使用Spring
RmiServiceExporter导出管理器

在客户端,我有一个由
RmiProxyFactoryBean
创建的管理器代理,以及一个通过该代理向服务器端的管理器注册的
Listener
实现

到目前为止还不错:
ListenerManager
有一个
Listener
,它调用它的回调,但是由于侦听器只是客户端对象的反序列化副本,回调在服务器端运行,而不是客户端


如何让Spring在服务器端为客户端侦听器生成一个代理,以便服务器调用的回调在客户端远程执行?当然,我不需要另一对(导出器、代理工厂)的相反方向?

A纯RMI解决方案:客户端侦听器对象需要实现
java.RMI.server.UnicastRemoteObject
。如果它这样做了,并且它的每个方法都抛出
RemoteException
,那么当它通过管理器代理传递到服务器时,所有内容都会自动连接起来,服务器端代理上对此侦听器的方法调用是对实际客户端对象上的方法的远程调用

这样就可以了,但是更好的做法是能够包装对象以便导出,而不需要特定的超类。我们可以使用CGLIB增强器将侦听器作为
UnicastRemoteObject
的子类“代理”,该子类也实现了服务接口。这仍然需要目标对象实现
java.rmi.Remote
并声明
抛出RemoteException

下一步是一个解决方案,它可以导出任意对象,以便远程调用它们的方法,而无需它们实现
remote
或声明
抛出RemoteException
。我们必须将此代理与现有的Spring基础架构集成,这可以通过一个新的
rmibasedxporter
实现来实现,该实现基于
RmiServiceExporter的非注册表位#prepare()
导出代理的RMI存根,并在
rmiclienterceptor.doInvoke的调用部分进行(MethodInvocation,RMInvocationHandler)
。我们需要能够获得服务接口的导出代理实例。我们可以根据Spring使用的显然是“导出”的方法对此进行建模非RMI接口。Spring代理接口为非RMI方法的调用生成
RMInvocationWrapper
,序列化方法细节和参数,然后在RMI连接的远端调用

  • 使用
    ProxyFactory
    rminvocationhandler
    实现来代理目标对象
  • 使用新的
    rmibasedxporter
    实现
    getObjectToExport()
    ,并使用
    UnicastRemoteObject#export(obj,0)
    导出它
  • 对于调用处理程序,
    rminvocationhandler.invoke(invocationFactory.createRemoteInvocation(invocation))
    ,带有一个
    DefaultRemoteInvocationFactory
  • 处理异常并适当包装,以避免看到
    未声明的hrowableexception
    s

因此,我们可以使用RMI导出任意对象。这意味着我们可以在客户端使用其中一个对象作为RMI服务器端对象上RMI方法调用的参数,当服务器端的反序列化存根调用了方法时,这些方法将在客户端执行。Magic。

按照Joe Kearney的解释,我已经创造了我的希望,什么都没有了

顺便说一句,请参考
对于“java.rmi.NoSuchObjectException:表中没有这样的对象”

只需在Joe的答案中添加一些代码即可

扩展RmiServiceExporter并获得对导出对象的访问权限:

public class RmiServiceExporter extends org.springframework.remoting.rmi.RmiServiceExporter {
    private Object remoteService;
    private String remoteServiceName;

    @Override
    public Remote getObjectToExport() {
        Remote exportedObject = super.getObjectToExport();

        if (getService() instanceof Remote && (
                getServiceInterface() == null || exportedObject.getClass().isAssignableFrom(getServiceInterface()))) {
            this.remoteService = exportedObject;
        }
        else {
            // RMI Invokers. 
            ProxyFactory factory = new ProxyFactory(getServiceInterface(), 
                    new RmiServiceInterceptor((RmiInvocationHandler) exportedObject, remoteServiceName));

            this.remoteService = factory.getProxy();
        }

        return exportedObject;
    }

    public Object getRemoteService()  {
        return remoteService;
    }

    /** 
     * Override to get access to the serviceName
     */
    @Override
    public void setServiceName(String serviceName) {
        this.remoteServiceName = serviceName;
        super.setServiceName(serviceName);
    }
}
代理中使用的侦听器(远程服务回调):

当使用此
RmiServiceExporter
导出服务时,我们可以通过以下方式发送rmi回调:

someRemoteService.someRemoteMethod(rmiServiceExporter.getRemoteService());

您可能希望将指向RMIUtil.java的链接更新为?
someRemoteService.someRemoteMethod(rmiServiceExporter.getRemoteService());