Spring远程服务----RMI服务实现远程调用

本文介绍了如何使用Spring框架结合RMI实现远程服务调用。主要内容包括RMI服务的重要类RMIProxyFactoryBean和RMIServiceExporter的使用,以及服务端RMIServer和客户端RMIConsumer的配置和测试。在服务端,详细阐述了XML和Java配置方式,并展示了启动类的配置。客户端部分介绍了如何调用远程服务并提供了单元测试的方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.简介

RMI技术是java最初远程调用的技术,在JDK1.1中被引入到Java平台中,它提供了一种强大的方式实现Java程序之间的交互。Spring简化了RMI模型,它提供了一个代理工厂bean,可以将RMI服务像本地JavaBean那样装配到spring应用中,另外spring提供了一个远程导出类RMIServiceExporter,用来简化spring管理的bean转化成为RMI服务的工作。

RMI是一种实现远程服务交互的好方法,但它存在着某些限制:

  • 在互联网上运行,很难穿越防火墙,RMI服务涉及两个端口,即注册端口和服务端口,RMI服务注册端口默认是1099,而服务端口是随机分配的,用于传送数据,所以在有防火墙的情况下,RMI客户端要穿越防火墙与RMI服务端进行通讯,需要让随机分配的端口固定下来。
  • RMI是基于Java的,这意味着客户端和服务端必须都是使用Java开发。因为RMI使用了Java的序列化机制,所以通过网络传输的对象类型必须是要保证在调用两端的java运行时是完全相同的版本。
  • 客户端配置为缓存服务端服务(cacheStub=true),如果服务端重新启动时,客户端调用将报错,解决方式:1.客户端设置为无缓存(cacheStub =false)。2.缓存调用失败后重新发起调用(refreshStubOnConnectFailure=true
1.1 重要的类
  • RMIServiceExporter:此类可以将任意Spring管理的bean发布为RMI服务,在服务端使用可以简化服务的发布。
    在这里插入图片描述
  • RMIProxyFactoryBean:Spring的一个工厂bean,该bean可以为RMI服务创建代理,将此类(RMI服务代理)声明为Spring管理的bean,依赖注入到接口bean中,可以实现客户端调用RMI远程服务。
    在这里插入图片描述
2.介绍

客户端和服务端都需要接口和实体类,为了减少重复类,将实体类和接口定义到一个单独项目里面,在客户端和服务端进行jar包引入。项目介绍如下:
——common:实体类和接口。
——RMIServer:服务端,实现common中的接口,提供RMI远程服务。
——RMIConsumer:客户端,将远程服务RMI的代理注入,进行服务的调用。

2.1 common
  • 实体类Account
    为了远程传输实体类,实体类要实现Serializable接口。
public class Account implements Serializable {

 private static final long serialVersionUID = 1L;
 private String name;

 public String getName() {
   return name;
 }
 public void setName(String name) {
   this.name = name;
 } 
 @Override
 public String toString() {
   return "Account [name=" + name + "]";
 }
 
}
  • 接口AccoutService
public interface AccountService {
  public void insertAccount(Account account);
  public List<Account> getAccounts(String name);
}
2.2 RMIServer
  • 接口实现类AccountServiceImpl
@Service
public class AccountServiceImpl implements AccountService{

  public void insertAccount(Account account) {
    return;
  }

  public List<Account> getAccounts(String name) {
    List<Account> accounts = new ArrayList<>();
    Account account = new Account();
    account.setName("DreamTech1113");
    accounts.add(account);
    return accounts;
  }
}
  • SpringBoot启动项目类Application
@SpringBootApplication
//xml配置方式,需要将applicationContext.xml配置加载
@ImportResource("classpath:applicationContext.xml")
//java类配置方式,需要配置@ComponentScan,
//@ComponentScan(basePackageClasses=RMIConfiguration.class)
public class Application {
  
  public static void main(String[] args) {
    SpringApplication.run(Application.class, args);
  }
}

——xml配置方式。

  • spring配置文件applicationContext.xml
<!-- 接口实现类 -->
 	<bean id="accountService" class="com.spring.service.AccountServiceImpl">
	</bean>
	<!--RmiServerExporter暴露服务端的接口-->
	<bean class="org.springframework.remoting.rmi.RmiServiceExporter">
	    <!-- does not necessarily have to be the same name as the bean to be exported -->
	    <property name="serviceName" value="AccountService"/>
	    <property name="service" ref="accountService"/>
	    <property name="serviceInterface" value="com.spring.service.AccountService"/>
	    <!-- defaults to 1099 -->
	    <property name="registryPort" value="1199"/>
	    <!--服务访问端口,不指定的情况下会随机分配-->
	    <!--<property name="servicePort" value="1200"/>-->
	</bean>

——Java类配置方式

  • Java类配置方式进行配置

   使用java类配置的时候,需要注解@Configuration表明这是配置类,另外需要注意的是springBoot项目启动类上注解@SpringBootApplication是个复合注解,包含了注解@ComponentScan,默认扫描的是和启动类Application同一个包下的注解。为了扫描配置类RMIConiguration的注解,在类Application上加入注解@ComponentScan(basePackages="com.spring")(当然如果和SpringBoot项目启动类在同一个目录下,不用额外@ComponentScan注解)。

@Configuration
public class RMIConfiguration {
  
  @Bean
  public RmiServiceExporter rmiExporter(AccountService accountService) {
    RmiServiceExporter rmiExporter = new RmiServiceExporter();
    //RMI远程服务的名称
    rmiExporter.setServiceName("AccountService");
    //通过@Bean注解将AccountService的实现AccountSeviceImpl注入到rmiExporter()方法中
    //acountService实际就是服务的实现
    rmiExporter.setService(accountService);
    //接口,AccountService是接口,定义在Common项目中
    rmiExporter.setServiceInterface(AccountService.class);
    //远程服务注册端口
    rmiExporter.setRegistryPort(1199);
    //远程服务访问端口,不指定会随机分配
    //rmiExporter.setServicePort(1200);
    return rmiExporter;
  }
 
}
  • pom.xml文件配置
    服务端项目RMIServer中pom.xml依赖主要是Common的jar包(定义了实体和接口)以及其他SpringBoot项目配置。
<parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.0.0.RELEASE</version>
    </parent>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!--实体和接口项目依赖-->
        <dependency>
         	<groupId>com.spring</groupId>
 			 <artifactId>common</artifactId>
  			<version>1.0.0</version>
        </dependency>
    </dependencies>
    <properties>
        <java.version>1.8</java.version>
    </properties>
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
2.3 RMIConsumer
  • 调用服务端的类RMIController
@RestController
public class RMIController {

  private AccountService accountService;
	//远程服务代理注入到本地
  @Autowired  
  public void setAccountService(AccountService accountService) {
    this.accountService = accountService;
  }
  
  @RequestMapping("/home")
  public List<Account> getAccount() {
    List<Account> accounts = accountService.getAccounts("name");
    return accounts;
  }
  
  @RequestMapping("/helloworld")
  public String getWorld() {
    return "hello";
  }
  
}
  • SpringBoot项目启动类Application
@SpringBootApplication
//加载spring配置文件
@ImportResource("classpath:applicationContext.xml")
public class Application {
    public static void main(String[] args) {
      SpringApplication.run(Application.class, args);
    }
}

——xml配置方式

  • spring配置文件applicationContext.xml
 	<bean class="com.spring.controller.RMIController">
    	<property name="accountService" ref="accountService"/>
	</bean>

	<!-- 远程服务代理 -->
	<bean id="accountService" class="org.springframework.remoting.rmi.RmiProxyFactoryBean">
	    <property name="serviceUrl" value="rmi://localhost:1199/AccountService"/>
	    <property name="serviceInterface" value="com.spring.service.AccountService"/>
	</bean>
    

——Java类配置方式

  • Java类配置方式进行配置
@Configuration
public class RMIClientConfiguration {

  @Bean
  public RmiProxyFactoryBean rmiProxy() {
    RmiProxyFactoryBean rmiProxy=new RmiProxyFactoryBean();
    //远程服务的接口,服务端对此接口进行了实现。
    rmiProxy.setServiceInterface(AccountService.class);
    //调用远程服务的地址,localhost(127.0.0.1)远程服务ip地址,1199是远程服务注册端口
   //AccountService是远程服务名称
    rmiProxy.setServiceUrl("rmi://localhost:1199/AccountService");
    return rmiProxy;
  }
}

同RMIServer一样,需要在启动类Application上加注解@ComponentScan(basePackages="com.spring")其中配置类RMIClientConfiguration位于包com.spring下面。

  • pom.xml
    同服务端项目RMIServer中的pom.xml配置。
3.测试调用
3.1 Controller层调用

在客户端写了controller层,可以通过访问页面的方式,页面访问RMIConsumer---->RMIServer方式返回远程调用结果。需要注意的是服务端RMIServer项目启动的tomcat端口是8080,客户端需要修改tomcat端口号(我这里修改为8889),在RMIConsumer项目/src/main/resources目录下创建一个文件名application.properties,内容如下:

server.port=8889

页面访问:http://localhost:8889/home,返回结果是:

[{“name”:“DreamTech1113”}]

3.2 单元测试

Spring配置文件方式(xml配置访问)可以通过单元测试方式来测试。

public class TestRMIInvoker {
  @Test   
  public void testDemo() {
    ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
    AccountService accountService =(AccountService) context.getBean("accountService");
    List<Account> accounts = accountService.getAccounts("name");
    System.out.println(accounts);
  }
}
4.参考

  1.Spring官方文档
  2.《Spring实战(Spring IN ACTION)》

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值