Обмен технологиями

Spring Boot интегрированная демонстрация быстрого запуска rmi

2024-07-12

한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina

1.Что такое РМИ?

RMI (удаленный вызов метода) — это удаленный вызов метода, который является основной идеей распределенного программирования. Существует множество технологий реализации удаленного вызова методов, например CORBA и WebService, обе из которых не зависят от каждого языка программирования. Java RMI — это механизм удаленного вызова методов, специально разработанный для среды Java. Это API Java, используемый для реализации удаленного вызова процедур (RPC). Он может напрямую передавать сериализованные объекты Java и распределенную сборку мусора. Его реализация зависит от JVM, поэтому она поддерживает вызовы от одной JVM к другой. В Java RMI удаленный сервер реализует определенные методы Java и предоставляет интерфейсы. Клиенту нужно только предоставить соответствующие параметры в соответствии с определением класса интерфейса, чтобы вызвать удаленный метод. Объект кодируется и передается посредством сериализации. Таким образом, обычная эксплуатация уязвимостей десериализации часто предполагает использование RMI, и вот что это значит. Протокол связи, на который опирается RMI, — это JRMP (Протокол удаленных сообщений Java, Протокол обмена удаленными сообщениями Java). Этот протокол настроен для Java и требует, чтобы и сервер, и клиент были написаны на Java.

интерактивный процесс

rmi_архитектура

реестр

Кратко процесс взаимодействия можно охарактеризовать следующим образом:

  1. Сначала запустите службу реестра RMI. При запуске вы можете указать порт, который прослушивает служба, или использовать порт по умолчанию (1099);
  2. Во-вторых, серверная сторона сначала создает экземпляр класса реализации, который предоставляет услуги локально, а затем регистрирует только что созданный экземпляр класса реализации в реестре RMI с помощью метода привязки или повторной привязки класса Naming/Context/Registry, предоставленного RMI, и предоставляет его внешнему миру. мир.
  3. Наконец, клиент использует локальный интерфейс и известное имя (то есть имя, предоставленное реестром RMI), чтобы получить класс реализации от службы RMI, используя метод поиска класса Naming/Context/Registry, предоставленного RMI. Таким образом, хотя локально класса реализации этого класса нет, все методы находятся в интерфейсе, а методы объекта можно вызывать удаленно;

2. Разработка кода

Экспериментальные цели

Поэкспериментируйте с простым сервисом rmi и вызовите его через клиент.

rmi-сервер

Это серверный проект, который в основном предоставляет интерфейс службы rmi.

pom.xml
  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <project xmlns="http://maven.apache.org/POM/4.0.0"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  5. <parent>
  6. <artifactId>rmi</artifactId>
  7. <groupId>com.et</groupId>
  8. <version>1.0-SNAPSHOT</version>
  9. </parent>
  10. <modelVersion>4.0.0</modelVersion>
  11. <artifactId>rmi-server</artifactId>
  12. <properties>
  13. <maven.compiler.source>8</maven.compiler.source>
  14. <maven.compiler.target>8</maven.compiler.target>
  15. </properties>
  16. <dependencies>
  17. <dependency>
  18. <groupId>org.springframework.boot</groupId>
  19. <artifactId>spring-boot-starter-web</artifactId>
  20. </dependency>
  21. <dependency>
  22. <groupId>org.springframework.boot</groupId>
  23. <artifactId>spring-boot-autoconfigure</artifactId>
  24. </dependency>
  25. <dependency>
  26. <groupId>org.springframework.boot</groupId>
  27. <artifactId>spring-boot-starter-test</artifactId>
  28. <scope>test</scope>
  29. </dependency>
  30. <dependency>
  31. <groupId>org.springframework.boot</groupId>
  32. <artifactId>spring-boot-starter-data-jpa</artifactId>
  33. </dependency>
  34. <dependency>
  35. <groupId>com.et</groupId>
  36. <artifactId>rmi-common</artifactId>
  37. <version>1.0-SNAPSHOT</version>
  38. </dependency>
  39. <dependency>
  40. <groupId>com.h2database</groupId>
  41. <artifactId>h2</artifactId>
  42. <version>1.4.200</version>
  43. </dependency>
  44. </dependencies>
  45. </project>
конфигурация
  1. package com.et.rmi.server.config;
  2. import com.et.rmi.server.dao.CustomerRepository;
  3. import com.et.rmi.server.model.Customer;
  4. import com.et.rmi.server.service.CustomerServiceImpl;
  5. import om.et.rmi.common.CustomerService;
  6. import org.springframework.boot.ApplicationArguments;
  7. import org.springframework.boot.ApplicationRunner;
  8. import org.springframework.context.annotation.Bean;
  9. import org.springframework.remoting.rmi.RmiServiceExporter;
  10. import org.springframework.stereotype.Component;
  11. import java.util.logging.Logger;
  12. @Component
  13. public class RmiServerApplicationRunner implements ApplicationRunner {
  14. private CustomerRepository repository;
  15. private CustomerServiceImpl customerService;
  16. private final Logger log = Logger.getLogger(this.getClass().getName());
  17. public RmiServerApplicationRunner(CustomerServiceImpl customerService) {
  18. this.customerService = customerService;
  19. }
  20. @Override
  21. public void run(ApplicationArguments args) throws Exception {
  22. Customer customer1 = new Customer("John", "Smith", "123-456-7890");
  23. customerService.saveCustomer(customer1);
  24. customerService.getCustomers().forEach(System.out::println);
  25. }
  26. @Bean
  27. public RmiServiceExporter customerServiceExporter() {
  28. RmiServiceExporter customerServiceExporter = new RmiServiceExporter();
  29. customerServiceExporter.setRegistryPort(1199);
  30. customerServiceExporter.setServiceName("customerService");
  31. customerServiceExporter.setServiceInterface(CustomerService.class);
  32. customerServiceExporter.setService(customerService);
  33. log.info("Started RMI Server");
  34. return customerServiceExporter;
  35. }
  36. }
услуга
  1. package com.et.rmi.server.service;
  2. import com.et.rmi.server.dao.CustomerRepository;
  3. import com.et.rmi.server.mapper.CustomerMapper;
  4. import com.et.rmi.server.model.Customer;
  5. import om.et.rmi.common.CustomerDTO;
  6. import om.et.rmi.common.CustomerService;
  7. import org.springframework.stereotype.Service;
  8. import java.util.List;
  9. @Service
  10. public class CustomerServiceImpl implements CustomerService {
  11. private CustomerRepository repository;
  12. public CustomerServiceImpl(CustomerRepository repository) {
  13. this.repository = repository;
  14. }
  15. @Override
  16. public CustomerDTO getCustomer(long id) {
  17. Customer customer = repository.findById(id).orElseThrow(IllegalArgumentException::new);
  18. CustomerMapper mapper = new CustomerMapper();
  19. CustomerDTO dto = mapper.mapToDTO(customer);
  20. System.out.println(dto);
  21. return dto;
  22. }
  23. public List<Customer> getCustomers() {
  24. return (List<Customer>)repository.findAll();
  25. }
  26. public void saveCustomer(Customer customer) {
  27. repository.save(customer);
  28. }
  29. }
дао
  1. package com.et.rmi.server.dao;
  2. import com.et.rmi.server.model.Customer;
  3. import org.springframework.data.repository.CrudRepository;
  4. import org.springframework.stereotype.Repository;
  5. import java.util.Optional;
  6. @Repository
  7. public interface CustomerRepository extends CrudRepository<Customer, Long> {
  8. Optional<Customer> findById(long id);
  9. }
картограф
  1. package com.et.rmi.server.mapper;
  2. import com.et.rmi.server.model.Customer;
  3. import om.et.rmi.common.CustomerDTO;
  4. public class CustomerMapper {
  5. public CustomerMapper() {
  6. }
  7. public CustomerDTO mapToDTO(Customer customer){
  8. CustomerDTO dto = new CustomerDTO();
  9. dto.setFirstName(customer.getFirstName());
  10. dto.setLastName(customer.getLastName());
  11. dto.setSocialSecurityCode(customer.getSocialSecurityCode());
  12. return dto;
  13. }
  14. }
модель
  1. package com.et.rmi.server.model;
  2. import javax.persistence.*;
  3. @Entity
  4. @SequenceGenerator(name = "CUST_SEQ", initialValue = 1_000_001)
  5. public class Customer {
  6. @Id
  7. @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "CUST_SEQ")
  8. private long id;
  9. private String firstName;
  10. private String lastName;
  11. private String socialSecurityCode;
  12. public Customer() {
  13. }
  14. public Customer(String firstName, String lastName, String socialSecurityCode) {
  15. this.firstName = firstName;
  16. this.lastName = lastName;
  17. this.socialSecurityCode = socialSecurityCode;
  18. }
  19. public long getId() {
  20. return id;
  21. }
  22. public String getFirstName() {
  23. return firstName;
  24. }
  25. public void setFirstName(String firstName) {
  26. this.firstName = firstName;
  27. }
  28. public String getLastName() {
  29. return lastName;
  30. }
  31. public void setLastName(String lastName) {
  32. this.lastName = lastName;
  33. }
  34. public String getSocialSecurityCode() {
  35. return socialSecurityCode;
  36. }
  37. public void setSocialSecurityCode(String socialSecurityCode) {
  38. this.socialSecurityCode = socialSecurityCode;
  39. }
  40. @Override
  41. public String toString() {
  42. return "Customer{" +
  43. "id=" + id +
  44. ", firstName='" + firstName + ''' +
  45. ", lastName='" + lastName + ''' +
  46. ", socialSecurityCode='" + socialSecurityCode + ''' +
  47. '}';
  48. }
  49. }
свойства приложения
spring.jpa.show-sql=false
spring.jpa.hibernate.ddl-auto=update
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.H2Dialect

rmi-клиент

Это клиентский проект, который в основном вызывает удаленный сервис rmi.

pom.xml
  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <project xmlns="http://maven.apache.org/POM/4.0.0"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  5. <parent>
  6. <artifactId>rmi</artifactId>
  7. <groupId>com.et</groupId>
  8. <version>1.0-SNAPSHOT</version>
  9. </parent>
  10. <modelVersion>4.0.0</modelVersion>
  11. <artifactId>rmi-cilent</artifactId>
  12. <properties>
  13. <maven.compiler.source>8</maven.compiler.source>
  14. <maven.compiler.target>8</maven.compiler.target>
  15. </properties>
  16. <dependencies>
  17. <dependency>
  18. <groupId>org.springframework.boot</groupId>
  19. <artifactId>spring-boot-starter-web</artifactId>
  20. </dependency>
  21. <dependency>
  22. <groupId>org.springframework.boot</groupId>
  23. <artifactId>spring-boot-autoconfigure</artifactId>
  24. </dependency>
  25. <dependency>
  26. <groupId>org.springframework.boot</groupId>
  27. <artifactId>spring-boot-starter-test</artifactId>
  28. <scope>test</scope>
  29. </dependency>
  30. <dependency>
  31. <groupId>com.et</groupId>
  32. <artifactId>rmi-common</artifactId>
  33. <version>1.0-SNAPSHOT</version>
  34. </dependency>
  35. </dependencies>
  36. </project>
контроллер
  1. package com.et.rmi.client.controller;
  2. import om.et.rmi.common.CustomerDTO;
  3. import om.et.rmi.common.CustomerService;
  4. import org.springframework.http.MediaType;
  5. import org.springframework.http.ResponseEntity;
  6. import org.springframework.remoting.rmi.RmiProxyFactoryBean;
  7. import org.springframework.stereotype.Controller;
  8. import org.springframework.web.bind.annotation.PathVariable;
  9. import org.springframework.web.bind.annotation.RequestMapping;
  10. import org.springframework.web.bind.annotation.RequestMethod;
  11. @Controller
  12. @RequestMapping(value = "customers")
  13. public class CustomerController {
  14. private RmiProxyFactoryBean proxyFactoryBean;
  15. public CustomerController(RmiProxyFactoryBean proxyFactoryBean) {
  16. this.proxyFactoryBean = proxyFactoryBean;
  17. }
  18. @RequestMapping(value = "{id}", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
  19. public ResponseEntity<CustomerDTO> getCustomer(@PathVariable long id) {
  20. CustomerService service = (CustomerService) proxyFactoryBean.getObject();
  21. CustomerDTO dto = service.getCustomer(id);
  22. return ResponseEntity.ok(dto);
  23. }
  24. }
конфигурация
  1. package com.et.rmi.client.config;
  2. import om.et.rmi.common.CustomerService;
  3. import org.springframework.context.annotation.Bean;
  4. import org.springframework.remoting.rmi.RmiProxyFactoryBean;
  5. import org.springframework.stereotype.Component;
  6. import org.springframework.util.StringUtils;
  7. import java.util.logging.Logger;
  8. @Component
  9. public class Config {
  10. public final Logger log = Logger.getLogger(this.getClass().getName());
  11. @Bean
  12. public RmiProxyFactoryBean proxyFactoryBean() {
  13. String remoteHost = System.getProperty("RMI_SERVER_HOST");
  14. if(StringUtils.isEmpty(remoteHost)){
  15. remoteHost="127.0.0.1";
  16. }
  17. String rmiHost = String.format("rmi://%s:1199/customerService", remoteHost);
  18. log.info("RMI Host name is " + rmiHost);
  19. RmiProxyFactoryBean proxy = new RmiProxyFactoryBean();
  20. proxy.setServiceInterface(CustomerService.class);
  21. proxy.setServiceUrl(rmiHost);
  22. proxy.afterPropertiesSet();
  23. return proxy;
  24. }
  25. }
свойства приложения
server.port=8081

rmi-общий

Это общедоступный пакет, на который должны ссылаться как сервер, так и клиент.

  1. package om.et.rmi.common;
  2. import java.io.Serializable;
  3. public class CustomerDTO implements Serializable {
  4. private String firstName;
  5. private String lastName;
  6. private String socialSecurityCode;
  7. public CustomerDTO() {
  8. }
  9. public String getFirstName() {
  10. return firstName;
  11. }
  12. public void setFirstName(String firstName) {
  13. this.firstName = firstName;
  14. }
  15. public String getLastName() {
  16. return lastName;
  17. }
  18. public void setLastName(String lastName) {
  19. this.lastName = lastName;
  20. }
  21. public String getSocialSecurityCode() {
  22. return socialSecurityCode;
  23. }
  24. public void setSocialSecurityCode(String socialSecurityCode) {
  25. this.socialSecurityCode = socialSecurityCode;
  26. }
  27. @Override
  28. public String toString() {
  29. final StringBuffer sb = new StringBuffer("CustomerDTO{");
  30. sb.append("firstName='").append(firstName).append(''');
  31. sb.append(", lastName='").append(lastName).append(''');
  32. sb.append(", socialSecurityCode='").append(socialSecurityCode).append(''');
  33. sb.append('}');
  34. return sb.toString();
  35. }
  36. }
  1. package om.et.rmi.common;
  2. public interface CustomerService {
  3. CustomerDTO getCustomer(long id);
  4. }

Выше приведены лишь некоторые ключевые коды. Все коды можно найти в репозитории кодов ниже.

репозиторий кода

3. Тест

  • Запустить службу rmi-сервера
  • Запустить службу rmi-клиента
  • Посетите http://127.0.0.1:8081/customers/1000001.
  • возвращаться{"firstName":"John","lastName":"Smith","socialSecurityCode":"123-456-7890"}

4. Цитата