Java RMI

Xuất bản trong nhóm
CHÀO! Hôm nay chúng ta sẽ xem xét một chủ đề khá thú vị: Java RMI. Đây là viết tắt của Gọi phương thức từ xa. Bạn có thể sử dụng RMI để cho phép hai chương trình giao tiếp với nhau, ngay cả khi chúng ở trên các máy tính khác nhau. Điều đó nghe có vẻ tuyệt phải không? :) Và nó không quá khó để làm! Trong bài học hôm nay, chúng ta sẽ phân tích các yếu tố của tương tác RMI và tìm ra cách cấu hình nó. Điều đầu tiên chúng ta cần là một máy khách và một máy chủ. Chúng ta không thực sự cần đi sâu vào thuật ngữ máy tính. Khi nói đến RMI, đây chỉ là hai chương trình. Một trong số chúng sẽ bao gồm một đối tượng và cái còn lại sẽ gọi các phương thức trên đối tượng đó. Gọi các phương thức của một đối tượng tồn tại trong một chương trình khác — bây giờ đó là điều chúng ta chưa làm được! Đó là thời gian để cung cấp cho nó một thử! :) Để tránh bị sa lầy, hãy' s giữ cho chương trình của chúng tôi đơn giản. Nói chung, một máy chủ thực hiện một số tính toán theo yêu cầu của khách hàng. Và vì vậy nó sẽ được với chúng tôi. Máy chủ của chúng tôi sẽ là một chương trình máy tính đơn giản. Nó sẽ chỉ có một phương pháp:nhân() . Nó sẽ nhân hai số do chương trình khách gửi đến, rồi trả về kết quả. Trước hết, chúng ta cần một giao diện:

import java.rmi.Remote;
import java.rmi.RemoteException;

public interface Calculator extends Remote {

   int multiply(int x, int y) throws RemoteException;
}
Tại sao chúng ta cần một giao diện? Bởi vì RMI dựa vào việc tạo proxy mà bạn đã học trong các bài học trước . Như bạn có thể nhớ, chúng tôi làm việc với proxy thông qua giao diện, không phải lớp. Có 2 yêu cầu quan trọng đối với giao diện của chúng ta!
  1. Nó phải mở rộng giao diện Remote.
  2. Tất cả các phương thức của nó phải đưa ra một RemoteException (IDE sẽ không tự động thực hiện việc này — bạn cần thêm điều này theo cách thủ công!).
Bây giờ chúng ta cần tạo một lớp máy chủ thực hiện giao diện Máy tính của chúng ta . RMI trong thực tế - 2Ở đây cũng vậy, mọi thứ khá đơn giản:

import java.rmi.RemoteException;

public class RemoteCalculationServer implements Calculator {

   @Override
   public int multiply(int x, int y) throws RemoteException {
       return x*y;
   }

}
Thực sự không có gì để bình luận ở đây :) Bây giờ chúng ta cần viết một chương trình máy chủ sẽ định cấu hình và chạy đối tượng máy tính của chúng ta. Nó sẽ trông giống thế này:

import java.rmi.AlreadyBoundException;
import java.rmi.Remote;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.rmi.server.UnicastRemoteObject;

public class ServerMain {

   public static final String UNIQUE_BINDING_NAME = "server.calculator";

   public static void main(String[] args) throws RemoteException, AlreadyBoundException, InterruptedException {

       final RemoteCalculationServer server = new RemoteCalculationServer();

       final Registry registry = LocateRegistry.createRegistry(2732);

       Remote stub = UnicastRemoteObject.exportObject(server, 0);
       registry.bind(UNIQUE_BINDING_NAME, stub);

       Thread.sleep(Integer.MAX_VALUE);

   }
}
Hãy tìm hiểu điều này :) Trong dòng đầu tiên, chúng tôi khai báo một số biến Chuỗi:

public static final String UNIQUE_BINDING_NAME = "server.calculator";
Chuỗi này là tên duy nhất của đối tượng từ xa. Chương trình máy khách của chúng tôi sử dụng tên này để tìm máy chủ của chúng tôi: bạn sẽ thấy điều này sau. Tiếp theo, chúng ta tạo đối tượng máy tính:

final RemoteCalculationServer server = new RemoteCalculationServer();
Mọi thứ đều rõ ràng ở đây. Điều gì xảy ra tiếp theo thú vị hơn:

final Registry registry = LocateRegistry.createRegistry(2732);
Đối tượng Registry này là một sổ đăng ký của các đối tượng từ xa. Đây là những đối tượng mà các chương trình khác có thể truy cập từ xa :) Chúng tôi đã chuyển số 2732 cho phương thức LocateRegistry.createRegistry() . Đây là số cổng — một số duy nhất mà các chương trình khác sẽ sử dụng để tìm sổ đăng ký đối tượng của chúng tôi (một lần nữa, bạn sẽ thấy điều này bên dưới). Di chuyển ngay... Hãy xem điều gì xảy ra trong dòng tiếp theo:

Remote stub = UnicastRemoteObject.exportObject(server, 0);
Chúng tôi tạo một sơ khai trong dòng này. Sơ khai đóng gói toàn bộ cuộc gọi từ xa. Có thể coi đây là yếu tố quan trọng nhất của RMI. Nó làm gì?
  1. Nó nhận tất cả thông tin về một cuộc gọi từ xa của một phương thức nào đó.
  2. Nếu phương thức có tham số, sơ khai sẽ giải tuần tự hóa chúng. Hãy chú ý đến điểm này! Các đối số mà bạn chuyển đến các phương thức được gọi từ xa phải được tuần tự hóa (xét cho cùng, chúng sẽ được truyền qua mạng). Đây không phải là vấn đề đối với chúng tôi — chúng tôi chỉ đang truyền số. Nhưng nếu bạn đang truyền đối tượng, đừng quên yêu cầu này!
  3. Sau đó, stub gọi phương thức mong muốn.
Chúng tôi chuyển đối tượng máy chủ máy tính của mình tới phương thức UnicastRemoteObject.exportObject() . Đây là cách chúng tôi có thể gọi các phương thức của nó từ xa. Chỉ còn một việc phải làm:

registry.bind(UNIQUE_BINDING_NAME, stub);
Chúng tôi "đăng ký" sơ khai của mình trong sổ đăng ký đối tượng từ xa dưới tên mà chúng tôi đã tạo ngay từ đầu. Bây giờ khách hàng sẽ có thể tìm thấy nó! Có lẽ bạn đã nhận thấy rằng chúng tôi đặt chủ đề chính của chương trình ở chế độ ngủ ở cuối:

Thread.sleep(Integer.MAX_VALUE);
Chúng tôi chỉ cần máy chủ chạy trong một thời gian dài. Trong IDE, chúng ta sẽ khởi chạy đồng thời hai phương thức main() : thứ nhất, phương thức main() của máy chủ (trong lớp ServerMain mà chúng ta đã viết), và thứ hai, phương thức main() của máy khách (trong lớp ClientMain , mà chúng tôi sẽ viết dưới đây). Điều quan trọng là chương trình máy chủ không bị chấm dứt trong khi chúng tôi khởi động máy khách, vì vậy chúng tôi chỉ đặt nó ở chế độ ngủ trong một thời gian dài. Trong mọi trường hợp, nó sẽ tiếp tục chạy :) Bây giờ chúng ta có thể chạy phương thức main() của máy chủ . Hãy để nó chạy và đợi chương trình khách gọi phương thức nào đó :) Bây giờ hãy viết chương trình khách! Nó sẽ gửi số đến máy chủ của chúng tôi để nhân lên.

import java.rmi.NotBoundException;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;

public class ClientMain {

   public static final String UNIQUE_BINDING_NAME = "server.calculator";

   public static void main(String[] args) throws RemoteException, NotBoundException {

       final Registry registry = LocateRegistry.getRegistry(2732);

       Calculator calculator = (Calculator) registry.lookup(UNIQUE_BINDING_NAME);

       int multiplyResult = calculator.multiply(20, 30);

       System.out.println(multiplyResult);
   }
}
Nó có vẻ đơn giản. Nhưng những gì đang xảy ra ở đây? Đầu tiên, client phải biết tên duy nhất của đối tượng mà nó sẽ gọi các phương thức từ xa. Theo đó, trong chương trình máy khách, chúng tôi đã tạo Chuỗi tĩnh cuối cùng công khai UNIQUE_BINDING_NAME = "server.calculator"; Biến đổi. Tiếp theo, trong phương thức main() , chúng ta có quyền truy cập vào sổ đăng ký của các đối tượng từ xa. Để thực hiện việc này, chúng ta cần gọi phương thức LocateRegistry.getRegistry() và chuyển số cổng được sử dụng để tạo sổ đăng ký của mình trong chương trình ServerMain (cổng 2732; số này chỉ là một ví dụ — bạn có thể thử sử dụng một số khác):

final Registry registry = LocateRegistry.getRegistry(2732);
Bây giờ chúng ta chỉ cần lấy đối tượng mong muốn từ sổ đăng ký! Điều này thật dễ dàng, bởi vì chúng ta biết tên riêng của nó!

Calculator calculator = (Calculator) registry.lookup(UNIQUE_BINDING_NAME);
Hãy chú ý đến việc đúc kiểu. Chúng tôi chuyển đối tượng đã nhận sang giao diện Máy tính , không phải lớp RemoteCalculationServer . Như chúng ta đã nói ở phần đầu của bài học, RMI dựa vào proxy, vì vậy các lệnh gọi từ xa chỉ khả dụng đối với các phương thức của một giao diện, không phải các phương thức của một lớp. Cuối cùng, chúng ta gọi phương thức multi() trên đối tượng của mình từ xa và xuất kết quả ra bàn điều khiển.

int multiplyResult = calculator.multiply(20, 30);
System.out.println(multiplyResult);
Phương thức main() của lớp ServerMain đã chạy từ lâu. Bây giờ là lúc chạy phương thức main() trong chương trình máy khách ( ClientMain )! Đầu ra bảng điều khiển:

600
Đó là nó! Chương trình của chúng tôi (thực ra là hai chương trình!) đã làm những gì nó phải làm :) Nếu bạn có thời gian và mong muốn, bạn có thể thêm chút gia vị cho chương trình này. Ví dụ: làm cho máy tính hỗ trợ bốn phép tính số học tiêu chuẩn và chuyển các số không phải ở dạng kiểu nguyên thủy mà ở dạng đối tượng Phép tính (int x, int y) . Hẹn gặp lại các bạn trong bài học tiếp theo! :)
Bình luận
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION