首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 綜合教學

Spring RMI 完整實例:服務端暴露與客戶端調用配置詳解

     編輯:Java 綜合教學

Spring RMI 完整實例:服務端暴露與客戶端調用配置詳解

Spring 對 Java RMI 進行了深度封裝,通過 RmiServiceExporter(服務端)與 RmiProxyFactoryBean(客戶端)實現透明化遠程調用。本文提供完整可運行的雙端配置代碼,涵蓋接口定義、序列化實體、服務導出、註冊端口、客戶端代理生成與調用驗證。

一、架構概覽

┌─────────────┐     RMI/JRMP      ┌─────────────┐
│  Server     │ ◄─────────────────► │  Client     │
│  (Exporter) │   10.7.3.12:9999  │  (Proxy)    │
└─────────────┘                   └─────────────┘
   Spring 容器                       Spring 容器
   RmiServiceExporter                RmiProxyFactoryBean

二、服務端實現

1. 共享接口與實體(需放在雙端共享模塊)

// UserRmiService.java
package com.goodfan.rmi.service;

public interface UserRmiService {
    String sayHello(User user);
}

// User.java
package com.goodfan.rmi.service;
import java.io.Serializable;

public class User implements Serializable {
    private static final long serialVersionUID = 8550373205815267923L;
    private String userName;
    // getter/setter...
}

2. 服務實現

// UserRmiServiceImpl.java
package com.goodfan.rmi.service.impl;
import com.goodfan.rmi.service.User;
import com.goodfan.rmi.service.UserRmiService;

public class UserRmiServiceImpl implements UserRmiService {
    @Override
    public String sayHello(User user) {
        return "Hello, " + user.getUserName();
    }
}

3. Spring 配置暴露服務

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

    <!-- 服務實現 Bean -->
    <bean id="userRmiServiceImpl" class="com.goodfan.rmi.service.impl.UserRmiServiceImpl" />

    <!-- RMI 服務導出器 -->
    <bean id="userRmi" class="org.springframework.remoting.rmi.RmiServiceExporter">
        <property name="service" ref="userRmiServiceImpl" />           <!-- 目標服務 -->
        <property name="serviceName" value="userRmi" />              <-- 註冊名稱 -->
        <property name="serviceInterface" value="com.goodfan.rmi.service.UserRmiService" /> <-- 遠程接口 -->
        <property name="registryPort" value="9999" />               <-- RMI 註冊表端口 -->
    </bean>
</beans>

4. 啟動類(綁定本機 IP)

// ServerTest.java
package com.goodfan.rmi.service;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class ServerTest {
    public static void main(String[] args) {
        // 關鍵:指定服務端綁定 IP,防止綁定 127.0.0.1 導致客戶端無法連接
        System.setProperty("java.rmi.server.hostname", "10.7.3.12");
        
        new ClassPathXmlApplicationContext("applicationContext.xml");
        System.out.println("RMI Server started on port 9999...");
    }
}

三、客戶端實現

1. Spring 配置代理

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

    <bean id="rmiProxy" class="org.springframework.remoting.rmi.RmiProxyFactoryBean">
        <property name="serviceUrl" value="rmi://10.7.3.12:9999/userRmi" /> <-- 完整 RMI URL -->
        <property name="serviceInterface" value="com.goodfan.rmi.service.UserRmiService" />
    </bean>
</beans>

2. 調用測試

// ClientTest.java
package com.goodfan.rmi.service;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class ClientTest {
    public static void main(String[] args) {
        ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext-client.xml");
        UserRmiService service = (UserRmiService) ctx.getBean("rmiProxy");
        
        User user = new User();
        user.setUserName("RMI");
        System.out.println(service.sayHello(user)); // 輸出:Hello, RMI
    }
}

四、關鍵技術點解析

組件 核心作用 關鍵屬性
RmiServiceExporter 將 Spring Bean 導出為 RMI 遠程服務 service、serviceName、serviceInterface、registryPort
RmiProxyFactoryBean 創建遠程服務的客戶端代理 serviceUrl、serviceInterface
java.rmi.server.hostname 指定服務端對外暴露的 IP(多網卡環境必須) 系統屬性,啟動前設置
序列化 參數/返回值跨 JVM 傳輸 實體必須實現 Serializable,建議顯式 serialVersionUID
註冊表 服務名稱 ↔ 存根 映射 默認端口 1099,此處配置 9999

五、常見問題與解決

  1. 連接被拒絕:檢查防火牆、java.rmi.server.hostname 是否為可訪問 IP、端口是否衝突。
  2. ClassNotFoundException (Stub):JDK 6+ 動態生成 Stub 無需預編譯,確保雙端 JDK 版本兼容。
  3. 序列化版本不匹配:雙端實體類 serialVersionUID 必須一致。
  4. 防火牆/NAT 穿透:RMI 使用隨機端口傳輸數據,需配置 java.rmi.server.hostname 並在防火牆開放註冊端口+隨機端口範圍,或使用 HTTP 隧道/VPN。
  5. 超時配置:客戶端可設置 sun.rmi.transport.tcp.responseTimeout 系統屬性控制調用超時。

六、Spring Boot 整合簡化配置

@Configuration
public class RmiConfig {
    @Bean
    public RmiServiceExporter userRmiExporter(UserRmiServiceImpl impl) {
        RmiServiceExporter exporter = new RmiServiceExporter();
        exporter.setService(impl);
        exporter.setServiceName("userRmi");
        exporter.setServiceInterface(UserRmiService.class);
        exporter.setRegistryPort(9999);
        return exporter;
    }

    @Bean
    public RmiProxyFactoryBean userRmiProxy() {
        RmiProxyFactoryBean proxy = new RmiProxyFactoryBean();
        proxy.setServiceUrl("rmi://10.7.3.12:9999/userRmi");
        proxy.setServiceInterface(UserRmiService.class);
        return proxy;
    }
}

七、總結

  • Spring RMI 封裝消除了樣板代碼,服務端 RmiServiceExporter、客戶端 RmiProxyFactoryBean 即可實現透明遠程調用
  • 核心要點:共享接口/實體、正確綁定 IP、序列化實現、註冊端口配置
  • RMI 適合內網低延遲同步調用,跨公網/微服務架構建議使用 gRPC、Dubbo、Spring Cloud OpenFeign 等現代 RPC 框架

掌握 Spring RMI 配置,能快速實現傳統系統集成、單體應用模塊解耦、測試環境服務模擬等場景。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved