Spring RMI refreshStubOnConnectFailure无效

时间:2016-01-06 02:59:52

标签: java spring rmi

我在这里阅读了以下博客文章, Reconnect RMI client after server restart

它声明当属性refreshStubOnConnectFailure设置为true时,我的客户端RMI将尝试重新连接到服务器。所以我在将更改添加到系统之前编写了以下代码来测试它。我启动了我的服务器,然后是这个测试程序。在服务器和客户端正在谈论的一些消息后,我停止了服务器。我得到了一个异常跟踪,但没有输入任何catch块。像往常一样,我很困惑,因为我认为至少有一个我的catch块会被执行。我的程序输出如下。

Main starting
Hi There Received
Hi There Received
Hi There Received
Jan 05, 2016 9:32:06 PM org.springframework.remoting.rmi.RmiProxyFactoryBean handleRemoteConnectFailure
WARNING: Could not connect to RMI service [rmi://127.0.0.1:1099/Ping] - retrying
Exception in thread "main" org.springframework.remoting.RemoteLookupFailureException: Lookup of RMI stub failed; nested exception is java.rmi.ConnectException: Connection refused to host: 127.0.0.1; nested exception is: 
java.net.ConnectException: Connection refused
at org.springframework.remoting.rmi.RmiClientInterceptor.lookupStub(RmiClientInterceptor.java:215)
at org.springframework.remoting.rmi.RmiClientInterceptor.refreshAndRetry(RmiClientInterceptor.java:326)
at org.springframework.remoting.rmi.RmiClientInterceptor.handleRemoteConnectFailure(RmiClientInterceptor.java:307)
at org.springframework.remoting.rmi.RmiClientInterceptor.invoke(RmiClientInterceptor.java:267)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:208)
at com.sun.proxy.$Proxy1.sayHello(Unknown Source)
at com.edvs.main.TestIt.main(TestIt.java:34)
Caused by: java.rmi.ConnectException: Connection refused to host: 127.0.0.1; nested exception is: 
java.net.ConnectException: Connection refused
at sun.rmi.transport.tcp.TCPEndpoint.newSocket(TCPEndpoint.java:619)
at sun.rmi.transport.tcp.TCPChannel.createConnection(TCPChannel.java:216)
at sun.rmi.transport.tcp.TCPChannel.newConnection(TCPChannel.java:202)
at sun.rmi.server.UnicastRef.newCall(UnicastRef.java:342)
at sun.rmi.registry.RegistryImpl_Stub.lookup(Unknown Source)
at java.rmi.Naming.lookup(Naming.java:101)
at org.springframework.remoting.rmi.RmiClientInterceptor.lookupStub(RmiClientInterceptor.java:200)
... 7 more
Caused by: java.net.ConnectException: Connection refused
at java.net.PlainSocketImpl.socketConnect(Native Method)
at java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:350)
at java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:206)
at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:188)
at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:392)
at java.net.Socket.connect(Socket.java:589)
at java.net.Socket.connect(Socket.java:538)
at java.net.Socket.<init>(Socket.java:434)
at java.net.Socket.<init>(Socket.java:211)
at sun.rmi.transport.proxy.RMIDirectSocketFactory.createSocket(RMIDirectSocketFactory.java:40)
at sun.rmi.transport.proxy.RMIMasterSocketFactory.createSocket(RMIMasterSocketFactory.java:148)
at sun.rmi.transport.tcp.TCPEndpoint.newSocket(TCPEndpoint.java:613)
... 13 more

我的代码如下:

package com.edvs.main;
import java.rmi.ConnectException;
import java.rmi.RemoteException
import org.springframework.context.ApplicationContext;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.edvs.service.PingService;

public class TestIt {

public static void main(String[] args) {

    String file = "bean.xml";
    ApplicationContext context = null;
    try {
        context = new ClassPathXmlApplicationContext(file);
    } catch (Exception e) {
        System.out.println("exception:" + e.getMessage());
        System.exit(99);
    }

    System.out.println("Main starting");
    PingService ps = (PingService) context.getBean("pingBean");
    boolean done = false;
    int count = 30;

    if (ps != null) {
        while (!done && count > 0) {
            try {
                if (ps.sayHello("Annapolis").equals("hi there")) {
                    System.out.println("Hi There Received");
                }
            } catch (ConnectException ce) {
                System.out.println("ConnectionException");
                /*
                 * Something happened with the server so see if it is
                 * something we should retry the connection.
                 */

                if (ce.getMessage().contains("Connection refused")) {
                    System.out.println("Connection Refused");
                }

            } catch (RemoteException e) {
                System.out.println("RemoteException:" + e.getMessage());
            }
            count--;

            try {
                Thread.yield();
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                done = true;
            }
        }
    }

    ((ConfigurableApplicationContext) context).close();

    System.out.println("Test has ended.");
  }
}

bean.xml:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans 
   http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
   http://www.springframework.org/schema/util
    http://www.springframework.org/schema/util/spring-util-2.5.xsd">


<bean id="pingBean" class="org.springframework.remoting.rmi.RmiProxyFactoryBean">
    <property name="serviceUrl" value="rmi://127.0.0.1:1099/Ping" />
    <property name="serviceInterface" value="com.edvs.service.PingService" />
    <property name="refreshStubOnConnectFailure" value="true" />
    <property name="lookupStubOnStartup" value="false" />
</bean>

没有抓住任何例外情况。应用程序刚刚终止。如果我注释掉refreshStubOnConnectFailure,则抛出ConnectionException异常,但我不知道重启服务器后如何重新启动连接。

为了完整性和其他人注视,我正在添加我的最终测试代码。它最初测试服务器,然后继续与服务器通信。

package com.edvs.main;
import java.net.MalformedURLException;
import java.rmi.ConnectException;
import java.rmi.Naming;
import java.rmi.NotBoundException;
import java.rmi.Remote;
import java.rmi.RemoteException;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.remoting.rmi.RmiProxyFactoryBean;

import com.edvs.service.PingService;

public class TestIt {
static Log log = LogFactory.getLog(TestIt.class.getName());

public static void main(String[] args) {

    String file = "bean.xml";

    ApplicationContext context = null;
    try {
        context = new ClassPathXmlApplicationContext(file);
    } catch (Exception e) {
        System.out.println("exception:" + e.getMessage());
        System.exit(99);
    }

    System.out.println("Main starting");
    log.info("foo");

    boolean done = false;
    int count = 30;

    RmiProxyFactoryBean rpfb = (RmiProxyFactoryBean) context.getBean("&pingBean");
    String serviceUrl = rpfb.getServiceUrl();

    /*
     * See if the server is there as we startup.
     */
    while (true) {
        if (null != isServerThere(serviceUrl)) {
            /*
             * The server is there so continue with our processing.
             */
            break;
        } else {
            /*
             * The server is not there so sleep and then try again.
             */
            try {
                Thread.yield();
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                System.exit(33);
            }
        }
    }

    PingService ps = (PingService) context.getBean("pingBean");

    try {
        log.info("Service Name:" + ps.getServiceName());
        log.info("all:" + ps.toString());
        log.info("serviceUrl:" + rpfb.getServiceUrl());

    } catch (RemoteException e1) {
        // TODO Auto-generated catch block
        e1.printStackTrace();
    } catch (SecurityException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }

    while (!done && count > 0) {

        try {
            if (ps.sayHello("Annapolis").equals("hi there")) {
                log.info("Hi There Received");
            }
        } catch (ConnectException ce) {
            log.info("ConnectionException");
            /*
             * Something happened with the server so see if it is something we
             * should retry the connection.
             */

            if (ce.getMessage().contains("Connection refused")) {
                log.info("Connection Refused");
                ps = (PingService) isServerThere(serviceUrl);
            }

        } catch (RemoteException e) {
            System.out.println("RemoteException:" + e.getMessage());
        }
        count--;

        try {
            Thread.yield();
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            done = true;
        }
    }

    ((ConfigurableApplicationContext) context).close();

    System.out.println("Test has ended.");
}

static private Remote isServerThere(String serviceUrl) {
    Remote remote = null;

    try {
        remote = Naming.lookup(serviceUrl);

    } catch (MalformedURLException | RemoteException | NotBoundException e) {
        log.error("Exception:" + e.getMessage());
    }

    return remote;
}
}

2 个答案:

答案 0 :(得分:0)

您正在向注册管理机构<{1}} 获取。由于Regsitry没有运行,因此无需重新查找就可以解决这个问题。这就是你需要解决的问题。

当您获得拒绝连接到远程对象时,您设置的属性将生效。

答案 1 :(得分:0)

我想我在这个论坛中找到了一个提到Naming.lookup()的答案。我更改了用于ConnectionException的catch块中的代码。该代码现在如下所示。

if (ce.getMessage().contains("Connection refused")) {
  log.info("Connection Refused");
  try {
    ps = (PingService)Naming.lookup("rmi://127.0.0.1:1099/Ping");
  } catch (MalformedURLException | RemoteException | NotBoundException e) {
    log.info("Naming Exception:" + e.getMessage());
  }
}

Naming.lookup()将继续失败,直到服务器进入备份。重新启动服务器后,将检索新的PingService对象,然后可以使用该对象。我认为这是正确的,并会感谢论坛的评论。