ITPub博客

首页 > 数据库 > 数据库开发技术 > Spring Boot集成rmi快速入门demo

Spring Boot集成rmi快速入门demo

原创 数据库开发技术 作者:hblog 时间:2024-07-08 21:48:17 0 删除 编辑

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编写的。

交互过程

  交互过程可简单概述为:

  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;
@Componentpublic 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; }
@Override public void run(ApplicationArguments args) throws Exception { Customer customer1 = new Customer("John", "Smith", "123-456-7890"); customerService.saveCustomer(customer1); customerService.getCustomers().forEach(System.out::println); }
@Bean public 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;
@Servicepublic class CustomerServiceImpl implements CustomerService {
private CustomerRepository repository;
public CustomerServiceImpl(CustomerRepository repository) { this.repository = repository; }
@Override public 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;
@Repositorypublic 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; }
@Override public String toString() { return "Customer{" + "id=" + id + ", firstName='" + firstName + '\'' + ", lastName='" + lastName + '\'' + ", socialSecurityCode='" + socialSecurityCode + '\'' + '}'; }}

application.properties

spring.jpa.show-sql=falsespring.jpa.hibernate.ddl-auto=updatespring.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;
@Componentpublic class Config {
public final Logger log = Logger.getLogger(this.getClass().getName());
@Bean public 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; }
@Override public 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);}

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

代码仓库

  • https://github.com/Harries/springboot-demo

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

  • http://www.liuhaihua.cn/archives/710836.html

原文作者:HBLOG;如有侵权,请联系管理员删除。

请登录后发表评论 登录
全部评论

注册时间:2022-05-04

  • 博文量
    210
  • 访问量
    111764