Spring Boot集成rmi快速入门demo

news2024/11/15 9:30:48

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;
    }

    @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;

@Service
public 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;

@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;
    }

    @Override
    public 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());

    @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);
}

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

代码仓库

  • 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™

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1908105.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Redis原理-数据结构

Redis原理篇 1、原理篇-Redis数据结构 1.1 Redis数据结构-动态字符串 我们都知道Redis中保存的Key是字符串&#xff0c;value往往是字符串或者字符串的集合。可见字符串是Redis中最常用的一种数据结构。 不过Redis没有直接使用C语言中的字符串&#xff0c;因为C语言字符串存…

高通开发系列 - 使用QFIL工具单刷某个镜像文件

By: fulinux E-mail: fulinux@sina.com Blog: https://blog.csdn.net/fulinus 喜欢的盆友欢迎点赞和订阅! 你的喜欢就是我写作的动力! 返回:专栏总目录 目录 背景过程记录背景 有时候设备中刷的是user版本,无法使用fastboot刷单个镜像,这个时候该怎么办呢? 要解决在user…

JavaScript中,正则表达式所涉及的api,解析、实例和总结

JS中正则的api包括以下&#xff1a; String#searchString#splitString#matchString#replaceRegExp#testRegExp#exec 1. String#search 查找输入串中第一个匹配正则的index&#xff0c;如果没有匹配的则返回-1。g修饰符对结果无影响 var string "abbbcbc"; var r…

2.硬盘和内存区别

2.2 磁盘比内存慢几万倍&#xff1f; 存储器方面的设备&#xff0c;分类比较多&#xff0c;那我们肯定不能只买一种存储器&#xff0c;比如你除了要买内存&#xff0c;还要买硬盘&#xff0c;而针对硬盘我们还可以选择是固态硬盘还是机械硬盘。 相信大家都知道内存和硬盘都属…

Spring的AOP进阶。(AOP的通知类型、通知顺序、切入点表达式和连接点。)

3. AOP进阶 AOP的基础知识学习完之后&#xff0c;下面我们对AOP当中的各个细节进行详细的学习。主要分为4个部分&#xff1a; 通知类型通知顺序切入点表达式连接点 我们先来学习第一部分通知类型。 3.1 通知类型 在入门程序当中&#xff0c;我们已经使用了一种功能最为强大…

物理层与数据通信基础:构建稳定网络的关键

本章主要讨论物理层的基本概念、数据通信的基础知识、几种常用的信道复用技术以及互联网接入技术。对于具备通信基础知识的读者&#xff0c;可以有选择地学习本章内容。 本章重点内容 物理层的任务数据通信的基本概念常用的信道复用技术常用的互联网接入技术 2.1 物理层的基…

产品经理技能揭秘:如何巧妙启发需求,引领市场新潮流

文章目录 引言一、需求启发的定义二、需求启发的艺术三、需求启发的重要性四、需求启发的流程五、需求启发的问题与挑战内部自身的问题与挑战&#xff1a;挑战一&#xff1a;知识的诅咒挑战二&#xff1a;做与定义的不同挑战三&#xff1a;沟通障碍挑战四&#xff1a;需求变更频…

LabVIEW在半导体自动化测试中的应用

半导体制造的复杂性和精密度要求极高&#xff0c;每一个生产步骤都需要严格的控制和监测。自动化测试设备在半导体制造中起到了关键作用&#xff0c;通过精密测量和数据分析&#xff0c;确保产品质量和生产效率。本文介绍如何使用LabVIEW结合研华硬件&#xff0c;开发一个用于半…

磁致伸缩液位计的应用领域

磁致伸缩液位计作为一种高精度、高稳定性的液位测量设备&#xff0c;在众多行业中都有着广泛的应用。接下来&#xff0c;我们将从多个角度详细探讨磁致伸缩液位计在不同领域的应用情况。 石油化工行业 在石油化工行业中&#xff0c;磁致伸缩液位计主要用于储罐、反应器和管道等…

实用性提升百分之一百!!!【ONLYOFFICE 8.1版本】全方位深度性能测评

目录 【ONLYOFFICE 8.1 版本】全方位深度性能测评 一、界面与用户体验 二、文字处理功能 表格处理功能 演示文稿功能 协作与共享功能 性能与稳定性 总结 【ONLYOFFICE 8.1 版本】全方位深度性能测评 在当今数字化办公的时代&#xff0c;办公软件的选择对于提高工作效率和…

全卷积网络之FCN图像语义分割

前言 FCN是一种用于图像语义分割的全卷积网络&#xff0c;可以端到端进行像素级预测。 语义分割 图像语义分割是图像处理和机器视觉技术中的重要一环&#xff0c;旨在对图像中的每个像素进行分类。与普通的分类任务不同&#xff0c;语义分割任务输出与输入大小相同的图像&…

ERP、CRM、MRP、PLM、APS、MES、WMS、SRM系统之间的关系

ERP系统是企业运营的神经中枢&#xff0c;整合了财务、人力资源、供应链等关键业务流程。CRM系统作为客户关系管理的专家&#xff0c;帮助企业深入了解客户需求&#xff0c;提升服务质量。MRP是物料需求的规划师&#xff0c;确保生产所需材料及时供应。PLM系统守护着产品从设计…

使用 Hugging Face 模型时遇到的问题

题意&#xff1a; I load a float32 Hugging Face model, cast it to float16, and save it. How can I load it as float16? 我加载了一个float32的Hugging Face模型&#xff0c;将其转换为float16&#xff0c;并保存了。我该如何以float16的形式加载它呢&#xff1f; 问题…

React@16.x(51)路由v5.x(16)- 手动实现文件目录参考

作为前面几篇文章的参考&#xff1a; 实现 Router实现 Route实现 Switch实现 withRouter实现 Link 和 NavLink 以上。

2024年06月CCF-GESP编程能力等级认证Python编程三级真题解析

本文收录于专栏《Python等级认证CCF-GESP真题解析》&#xff0c;专栏总目录&#xff1a;点这里&#xff0c;订阅后可阅读专栏内所有文章。 一、单选题&#xff08;每题 2 分&#xff0c;共 30 分&#xff09; 第 1 题 小杨父母带他到某培训机构给他报名参加CCF组织的GESP认证…

海南云亿商务咨询有限公司口碑怎么样?

在数字化浪潮席卷全球的今天&#xff0c;电商行业正以前所未有的速度发展。抖音作为短视频领域的佼佼者&#xff0c;其电商功能更是为众多品牌和企业打开了全新的销售渠道。海南云亿商务咨询有限公司&#xff0c;作为抖音电商服务领域的佼佼者&#xff0c;正以其专业的服务和创…

PHP源码:新闻门户系统(附管理后台+前台)

一. 前言 今天小编给大家带来了一款可学习&#xff0c;可商用的&#xff0c;新闻门户系统 源码&#xff0c;支持二开&#xff0c;无加密。项目可以扩展为个人博客&#xff0c;和一些社交论坛网址。主要功能&#xff1a;支持文章管理&#xff0c;评论管理&#xff0c;分类管理等…

kafka系列之offset超强总结及消费后不提交offset情况的分析总结

概述 每当我们调用Kafka的poll()方法或者使用Spring的KafkaListener(其实底层也是poll()方法)注解消费Kafka消息时&#xff0c;它都会返回之前被写入Kafka的记录&#xff0c;即我们组中的消费者还没有读过的记录。 这意味着我们有一种方法可以跟踪该组消费者读取过的记录。 如前…

安全防御第三天(笔记持续更新)

1.接口类型以及作用 接口 --- 物理接口 三层口 --- 可以配置IP地址的接口 二层口 普通二层口 接口对 --- “透明网线” --- 可以将一个或者两个接口配置成为接口对&#xff0c;则 数据从一个接口进&#xff0c;将不需要查看MAC地址表&#xff0c;直接从另一个接口出&#xff1b…

找回消失的SOLIDWORKS PDM“蓝莓”图标

SOLIDWORKS 产品数据管理 (PDM) 解决方案可帮助您控制设计数据&#xff0c;并且从本质上改进您的团队就产品开发进行管理和协作的方式。使用 SOLIDWORKS PDM Professional&#xff0c;您的团队能够&#xff1a;1. 安全地存储和索引设计数据以实现快速检索&#xff1b;2. 打消关…