当前位置: 首页 > news >正文

Spring Boot集成rmi快速入门demo

1.什么是rmi?

RMI(Remote Method Invocation)即远程方法调用,是分布式编程中的一个基本思想。实现远程方法调用的技术有很多,比如CORBA、WebService,这两种都是独立于各个编程语言的。 而Java RMI是专为Java环境设计的远程方法调用机制,是一种用于实现远程调用(RPC,Remote Procedure Call)的Java API,能直接传输序列化后的Java对象和分布式垃圾收集。它的实现依赖于JVM,因此它支持从一个JVM到另一个JVM的调用。 在Java RMI中,远程服务器实现具体的Java方法并提供接口,客户端本地仅需根据接口类的定义,提供相应的参数即可调用远程方法,其中对象是通过序列化方式进行编码传输的。所以平时说的反序列化漏洞的利用经常是涉及到RMI,就是这个意思。 RMI依赖的通信协议为JRMP(Java Remote Message Protocol,Java远程消息交换协议),该协议是为Java定制的,要求服务端与客户端都必须是Java编写的。

交互过程

rmi_architecture

registry

  交互过程可简单概述为:

  1. 首先,启动RMI Registry服务,启动时可以指定服务监听的端口,也可以使用默认的端口(1099);
  2. 其次,Server端在本地先实例化一个提供服务的实现类,然后通过RMI提供的Naming/Context/Registry等类的bind或rebind方法将刚才实例化好的实现类注册到RMI Registry上并对外暴露一个名称;
  3. 最后,Client端通过本地的接口和一个已知的名称(即RMI Registry暴露出的名称),使用RMI提供的Naming/Context/Registry等类的lookup方法从RMI Service那拿到实现类。这样虽然本地没有这个类的实现类,但所有的方法都在接口里了,便可以实现远程调用对象的方法了;

2.代码工程

实验目标

实验一个简单rmi服务,并且通过客户端调用它

rmi-server

这是一个服务端工程,主要提供rmi service接口

pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><parent><artifactId>rmi</artifactId><groupId>com.et</groupId><version>1.0-SNAPSHOT</version></parent><modelVersion>4.0.0</modelVersion><artifactId>rmi-server</artifactId><properties><maven.compiler.source>8</maven.compiler.source><maven.compiler.target>8</maven.compiler.target></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-autoconfigure</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-jpa</artifactId></dependency><dependency><groupId>com.et</groupId><artifactId>rmi-common</artifactId><version>1.0-SNAPSHOT</version></dependency><dependency><groupId>com.h2database</groupId><artifactId>h2</artifactId><version>1.4.200</version></dependency></dependencies>
</project>
config
package com.et.rmi.server.config;import com.et.rmi.server.dao.CustomerRepository;import com.et.rmi.server.model.Customer;
import com.et.rmi.server.service.CustomerServiceImpl;
import om.et.rmi.common.CustomerService;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.context.annotation.Bean;
import org.springframework.remoting.rmi.RmiServiceExporter;
import org.springframework.stereotype.Component;import java.util.logging.Logger;@Component
public class RmiServerApplicationRunner implements ApplicationRunner {private CustomerRepository repository;private CustomerServiceImpl customerService;private final Logger log = Logger.getLogger(this.getClass().getName());public RmiServerApplicationRunner(CustomerServiceImpl customerService) {this.customerService = customerService;}@Overridepublic void run(ApplicationArguments args) throws Exception {Customer customer1 = new Customer("John", "Smith", "123-456-7890");customerService.saveCustomer(customer1);customerService.getCustomers().forEach(System.out::println);}@Beanpublic RmiServiceExporter customerServiceExporter() {RmiServiceExporter customerServiceExporter = new RmiServiceExporter();customerServiceExporter.setRegistryPort(1199);customerServiceExporter.setServiceName("customerService");customerServiceExporter.setServiceInterface(CustomerService.class);customerServiceExporter.setService(customerService);log.info("Started RMI Server");return customerServiceExporter;}
}
service
package com.et.rmi.server.service;import com.et.rmi.server.dao.CustomerRepository;import com.et.rmi.server.mapper.CustomerMapper;
import com.et.rmi.server.model.Customer;
import om.et.rmi.common.CustomerDTO;
import om.et.rmi.common.CustomerService;
import org.springframework.stereotype.Service;import java.util.List;@Service
public class CustomerServiceImpl implements CustomerService {private CustomerRepository repository;public CustomerServiceImpl(CustomerRepository repository) {this.repository = repository;}@Overridepublic CustomerDTO getCustomer(long id) {Customer customer = repository.findById(id).orElseThrow(IllegalArgumentException::new);CustomerMapper mapper = new CustomerMapper();CustomerDTO dto = mapper.mapToDTO(customer);System.out.println(dto);return dto;}public List<Customer> getCustomers() {return (List<Customer>)repository.findAll();}public void saveCustomer(Customer customer) {repository.save(customer);}
}
dao
package com.et.rmi.server.dao;import com.et.rmi.server.model.Customer;
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;import java.util.Optional;@Repository
public interface CustomerRepository extends CrudRepository<Customer, Long> {Optional<Customer> findById(long id);
}
mapper
package com.et.rmi.server.mapper;import com.et.rmi.server.model.Customer;import om.et.rmi.common.CustomerDTO;public class CustomerMapper {public CustomerMapper() {}public CustomerDTO mapToDTO(Customer customer){CustomerDTO dto = new CustomerDTO();dto.setFirstName(customer.getFirstName());dto.setLastName(customer.getLastName());dto.setSocialSecurityCode(customer.getSocialSecurityCode());return dto;}
}
model
package com.et.rmi.server.model;import javax.persistence.*;@Entity
@SequenceGenerator(name = "CUST_SEQ", initialValue = 1_000_001)
public class Customer {@Id@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "CUST_SEQ")private long id;private String firstName;private String lastName;private String socialSecurityCode;public Customer() {}public Customer(String firstName, String lastName, String socialSecurityCode) {this.firstName = firstName;this.lastName = lastName;this.socialSecurityCode = socialSecurityCode;}public long getId() {return id;}public String getFirstName() {return firstName;}public void setFirstName(String firstName) {this.firstName = firstName;}public String getLastName() {return lastName;}public void setLastName(String lastName) {this.lastName = lastName;}public String getSocialSecurityCode() {return socialSecurityCode;}public void setSocialSecurityCode(String socialSecurityCode) {this.socialSecurityCode = socialSecurityCode;}@Overridepublic String toString() {return "Customer{" +"id=" + id +", firstName='" + firstName + '\'' +", lastName='" + lastName + '\'' +", socialSecurityCode='" + socialSecurityCode + '\'' +'}';}
}
application.properties
spring.jpa.show-sql=false
spring.jpa.hibernate.ddl-auto=update
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.H2Dialect

rmi-client

这是一个客户端工程,主要调用远程的rmi服务

pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><parent><artifactId>rmi</artifactId><groupId>com.et</groupId><version>1.0-SNAPSHOT</version></parent><modelVersion>4.0.0</modelVersion><artifactId>rmi-cilent</artifactId><properties><maven.compiler.source>8</maven.compiler.source><maven.compiler.target>8</maven.compiler.target></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-autoconfigure</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><dependency><groupId>com.et</groupId><artifactId>rmi-common</artifactId><version>1.0-SNAPSHOT</version></dependency></dependencies>
</project>
controller
package com.et.rmi.client.controller;import om.et.rmi.common.CustomerDTO;
import om.et.rmi.common.CustomerService;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.remoting.rmi.RmiProxyFactoryBean;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;@Controller
@RequestMapping(value = "customers")
public class CustomerController {private RmiProxyFactoryBean proxyFactoryBean;public CustomerController(RmiProxyFactoryBean proxyFactoryBean) {this.proxyFactoryBean = proxyFactoryBean;}@RequestMapping(value = "{id}", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)public ResponseEntity<CustomerDTO> getCustomer(@PathVariable long id) {CustomerService service = (CustomerService) proxyFactoryBean.getObject();CustomerDTO dto = service.getCustomer(id);return ResponseEntity.ok(dto);}
}

config
package com.et.rmi.client.config;import om.et.rmi.common.CustomerService;
import org.springframework.context.annotation.Bean;
import org.springframework.remoting.rmi.RmiProxyFactoryBean;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;import java.util.logging.Logger;@Component
public class Config {public final Logger log = Logger.getLogger(this.getClass().getName());@Beanpublic RmiProxyFactoryBean proxyFactoryBean() {String remoteHost = System.getProperty("RMI_SERVER_HOST");if(StringUtils.isEmpty(remoteHost)){remoteHost="127.0.0.1";}String rmiHost = String.format("rmi://%s:1199/customerService", remoteHost);log.info("RMI Host name is " + rmiHost);RmiProxyFactoryBean proxy = new RmiProxyFactoryBean();proxy.setServiceInterface(CustomerService.class);proxy.setServiceUrl(rmiHost);proxy.afterPropertiesSet();return proxy;}
}
application.properties
server.port=8081

rmi-common

这是一个公共包,server和client都要引用

package om.et.rmi.common;import java.io.Serializable;public class CustomerDTO implements Serializable {private String firstName;private String lastName;private String socialSecurityCode;public CustomerDTO() {}public String getFirstName() {return firstName;}public void setFirstName(String firstName) {this.firstName = firstName;}public String getLastName() {return lastName;}public void setLastName(String lastName) {this.lastName = lastName;}public String getSocialSecurityCode() {return socialSecurityCode;}public void setSocialSecurityCode(String socialSecurityCode) {this.socialSecurityCode = socialSecurityCode;}@Overridepublic String toString() {final StringBuffer sb = new StringBuffer("CustomerDTO{");sb.append("firstName='").append(firstName).append('\'');sb.append(", lastName='").append(lastName).append('\'');sb.append(", socialSecurityCode='").append(socialSecurityCode).append('\'');sb.append('}');return sb.toString();}
}
package om.et.rmi.common;public interface CustomerService {CustomerDTO getCustomer(long id);
}

以上只是一些关键代码,所有代码请参见下面代码仓库

代码仓库

  • GitHub - Harries/springboot-demo: a simple springboot demo with some components for example: redis,solr,rockmq and so on.

3.测试

  • 启动rmi-server服务
  • 启动rmi-client服务
  • 访问http://127.0.0.1:8081/customers/1000001
  • 返回{"firstName":"John","lastName":"Smith","socialSecurityCode":"123-456-7890"}

4.引用

  • https://www.tutorialspoint.com/java_rmi/java_rmi_introduction.htm
  • https://docs.oracle.com/javase/8/docs/technotes/guides/rmi/index.html
  • Spring Boot集成rmi快速入门demo | Harries Blog™

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • Java面试题--JVM大厂篇之深入探讨Serial GC的应用场景
  • 【Python】找Excel重复行
  • python中 is 的意义和用法
  • 基于深度学习的频谱分析
  • 数据库之索引(四)
  • C#用链表和数组实现队列
  • 从“钓”到“管”:EasyCVR一体化视频解决方案助力水域安全管理
  • 基于Wireshark和TiWsPC(Wireshark Packet Converter)的Zigbee抓包
  • 用R在地图上绘制网络图的三种方法
  • 第五十二章 生成的 WSDL 的详细信息 - 命名空间声明
  • android.bp 编译 顺序
  • Mac本地部署大模型-单机运行
  • 不可不看,年轻人必须丢掉的10条幼稚职场心理
  • hive中reverse函数
  • 一 、分布式软总线原理
  • 4月23日世界读书日 网络营销论坛推荐《正在爆发的营销革命》
  • golang 发送GET和POST示例
  • HTML5新特性总结
  • JavaScript HTML DOM
  • Java多线程(4):使用线程池执行定时任务
  • js ES6 求数组的交集,并集,还有差集
  • leetcode-27. Remove Element
  • mockjs让前端开发独立于后端
  • npx命令介绍
  • Python实现BT种子转化为磁力链接【实战】
  • SAP云平台里Global Account和Sub Account的关系
  • Spring Boot快速入门(一):Hello Spring Boot
  • vue-router 实现分析
  • Vue官网教程学习过程中值得记录的一些事情
  • Xmanager 远程桌面 CentOS 7
  • 百度贴吧爬虫node+vue baidu_tieba_crawler
  • 翻译--Thinking in React
  • - 概述 - 《设计模式(极简c++版)》
  • 聊聊flink的BlobWriter
  • 三分钟教你同步 Visual Studio Code 设置
  • 温故知新之javascript面向对象
  • Linux权限管理(week1_day5)--技术流ken
  • #LLM入门|Prompt#2.3_对查询任务进行分类|意图分析_Classification
  • #QT(串口助手-界面)
  • #stm32驱动外设模块总结w5500模块
  • $L^p$ 调和函数恒为零
  • (16)Reactor的测试——响应式Spring的道法术器
  • (19)夹钳(用于送货)
  • (Matlab)遗传算法优化的BP神经网络实现回归预测
  • (pytorch进阶之路)扩散概率模型
  • (翻译)Entity Framework技巧系列之七 - Tip 26 – 28
  • (附源码)php投票系统 毕业设计 121500
  • (附源码)springboot码头作业管理系统 毕业设计 341654
  • (论文阅读22/100)Learning a Deep Compact Image Representation for Visual Tracking
  • (三)Pytorch快速搭建卷积神经网络模型实现手写数字识别(代码+详细注解)
  • (转)平衡树
  • (自用)learnOpenGL学习总结-高级OpenGL-抗锯齿
  • *Django中的Ajax 纯js的书写样式1
  • .Net MVC4 上传大文件,并保存表单
  • .NET 应用架构指导 V2 学习笔记(一) 软件架构的关键原则