Java RMI导致" NoSuchObjectException"

时间:2015-10-06 13:26:11

标签: java rmi

我遇到了JAVA RMI的问题。

我有一个运行的java ee应用程序,它使用rmi来调用特定的方法,这些方法必须专门为每个客户实现。 供应商给了我一个示例RMI接口实现,以展示如何运行特定的主机接口。 原始的codefragment看起来像发布了example1。 接口正在运行,但每隔2到3天就会停止工作,没有任何已知原因。接口'日志看起来仍然在运行。 调用接口的glassfish服务器显示如下日志条目:

[#| 2015-10-01T16:27:53.446 + 0200 |严重| glassfish3.1.2 | javax.enterprise.system.std.com.sun.enterprise.server.logging | _ThreadID = 106; _ThreadName = Thread- 2; | egatingMethodAccessorImpl.invoke(未知来源)     at java.lang.reflect.Method.invoke(Unknown Source)     ...

应用程序错误日志显示如下条目:

2015-10-05 08:44:07,819 [http-thread-pool-8080(4)]错误medexter.arden.server.engine.DelegatingHostInterface - 远程接口上的evaluateRead方法无法正常工作。 java.rmi.NoSuchObjectException:表中没有这样的对象     at sun.rmi.transport.StreamRemoteCall.exceptionReceivedFromServer(Unknown Source)     ...

我找到了几个像这样的线程: java.rmi.NoSuchObjectException: no such object in table

告诉我垃圾收集可能是负责任的,并且必须静态保存注册表以防止GC破坏对象。 与此同时,我尝试了不同的方法。我的最后一个(以某种方式显示我的解压 - 每24小时重新启动界面不应该是黄金解决方案)发布在example2中。 目前,我生成一个可执行jar文件并将其作为应用程序启动。我希望以后能够将它作为一项服务运行,但首先它应该没有任何错误。

有人有想法,所描述行为的原因是什么? 对给定代码的任何改进都是适用的。我只想让这些东西工作,而不是每隔几天就失去联系。

非常感谢, 马丁

示例1:

import java.rmi.AlreadyBoundException;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.rmi.server.UnicastRemoteObject;


public class SampleRMIProvider {

  private static RmiRegistryThread thr;

  public static void main(String[] args) {
    SampleRMIProvider prv = new SampleRMIProvider();
    prv.init();
  }

  public void init(){
    SampleRMIProvider.thr = new RmiRegistryThread();
    thr.start();
  }

  public class RmiRegistryThread extends Thread {

    public boolean run = true;

    @Override
    public void run() {
      System.err.println("thread start");
      String name = "RMIHostInterface";
      int servicePorti = Integer.parseInt("18989");
      try {
        RmiHostInterface engine = new RmiHostInterfaceImpl();
        RmiHostInterface stub = (RmiHostInterface) UnicastRemoteObject.exportObject(engine, 0);
        Registry registry;
        try {
          registry = LocateRegistry.createRegistry(servicePorti);
        } catch (RemoteException e) {
          registry = LocateRegistry.getRegistry(servicePorti);
        }
        registry.bind(name, stub);
      } catch (RemoteException e) {
        e.printStackTrace();
      } catch (AlreadyBoundException e) {
        e.printStackTrace();
      }
      try {
        while (this.run) {
          Thread.sleep(10000);
        }     
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
    }
  }
}

示例2:

import java.rmi.AlreadyBoundException;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.rmi.server.UnicastRemoteObject;


public class SampleRMIProvider extends Thread{

    private static Registry r = null;

    @Override
    public void run() {
        String name = "RMIHostInterface";
        int servicePorti = Integer.parseInt("20002"); //18989

        try {
            RmiHostInterface engine = new SampleInterfaceImpl();
            RmiHostInterface stub = (RmiHostInterface) UnicastRemoteObject.exportObject(engine, 0);

            try {
                SampleRMIProvider.r = LocateRegistry.createRegistry(servicePorti);
            } catch (RemoteException e) {
                SampleRMIProvider.r = LocateRegistry.getRegistry(servicePorti);
            }
            SampleRMIProvider.r.bind(name, stub);
        } catch (RemoteException e) {
            e.printStackTrace();
        } catch (AlreadyBoundException e) {
            e.printStackTrace();
        } 
        System.err.println("RMI Interface created...");
        try{
            while(true){
                Thread.sleep(10000);
            }
        }
        catch (InterruptedException e) {
             e.printStackTrace();
        }
    }

    public static void main(String[] args) {

        try {
            while (true) {
                //RMI Interface instanzieren
                SampleRMIProvider provider = new SampleRMIProvider();
                provider.start();
                //Ein Tag pause
                Thread.sleep(86400000);
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

}

二〇一五年十月十四日 最后 - 这个最小的例子显示了一个对我有用的解决方案。感谢您提供有用的建议。

import java.rmi.AlreadyBoundException;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.rmi.server.UnicastRemoteObject;

public class SampleRMIProvider{

private static Registry r = null;
private static SampleHostInterfaceImpl hif = null;
private static RmiHostInterface stub = null;

SampleRMIProvider(){
    try{
        SampleRMIProvider.r.bind("RMIHostInterface", SampleRMIProvider.stub);
    }
    catch(RemoteException | AlreadyBoundException e){
        e.printStackTrace();
    }
}

public static void main(String[] args) {

    //setup static references to prevent from beeing collected by GC
    try {
        SampleRMIProvider.hif = new SampleHostInterfaceImpl();  
        SampleRMIProvider.stub = (RmiHostInterface) UnicastRemoteObject.exportObject(SampleRMIProvider.hif, 0);
        try {
            SampleRMIProvider.r = LocateRegistry.createRegistry(20002);
        } catch (RemoteException e) {
            SampleRMIProvider.r = LocateRegistry.getRegistry(20002);
        }

    } catch (RemoteException e) {
        e.printStackTrace();
    }
    new SampleRMIProvider();
}
}

1 个答案:

答案 0 :(得分:0)

  • 当异常的Javadoc中记录原因时,我不知道你的意思是什么,没有已知的原因。

  • 您说您已经读过注册表引用必须是静态的,但您在任何地方都没有静态注册表引用。

尝试实施。