John Squirrels
ระดับ
San Francisco

Java RMI

เผยแพร่ในกลุ่ม
สวัสดี! วันนี้เราจะพิจารณาหัวข้อที่ค่อนข้างน่าสนใจ: Java RMI นี่หมายถึงการเรียกใช้เมธอดระยะไกล คุณสามารถใช้ RMI เพื่ออนุญาตให้สองโปรแกรมสื่อสารระหว่างกันได้ แม้ว่าโปรแกรมเหล่านั้นจะอยู่บนคอมพิวเตอร์คนละเครื่องก็ตาม เสียงที่เย็น? :) และมันก็ไม่ยากที่จะทำ! ในบทเรียนวันนี้ เราจะวิเคราะห์องค์ประกอบของการโต้ตอบ RMI และหาวิธีกำหนดค่า สิ่งแรกที่เราต้องการคือไคลเอ็นต์และเซิร์ฟเวอร์ เราไม่จำเป็นต้องลงลึกในคำศัพท์เกี่ยวกับคอมพิวเตอร์ เมื่อพูดถึง RMI นี่เป็นเพียงสองโปรแกรมเท่านั้น หนึ่งในนั้นจะรวมวัตถุและอีกวิธีหนึ่งจะเรียกใช้เมธอดบนวัตถุนั้น วิธีการเรียกของวัตถุที่มีอยู่ในโปรแกรมอื่น - ตอนนี้เป็นสิ่งที่เรายังไม่ได้ทำ! ได้เวลาลองแล้ว! :) เพื่อไม่ให้จมดิ่ง ทำให้โปรแกรมของเราเรียบง่าย โดยทั่วไป เซิร์ฟเวอร์จะทำการคำนวณบางอย่างตามที่ลูกค้าร้องขอ แล้วมันก็จะอยู่กับเรา เซิร์ฟเวอร์ของเราจะเป็นโปรแกรมคิดเลขอย่างง่าย มันจะมีวิธีเดียวคือคูณ () . มันจะคูณสองตัวเลขที่โปรแกรมไคลเอ็นต์ส่งมาให้ แล้วส่งกลับผลลัพธ์ ก่อนอื่นเราต้องการอินเทอร์เฟซ:

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

public interface Calculator extends Remote {

   int multiply(int x, int y) throws RemoteException;
}
ทำไมเราต้องมีส่วนต่อประสาน? เนื่องจาก RMI อาศัยการสร้างพร็อกซี ซึ่งคุณได้ศึกษาในบทเรียนที่ผ่านมา อย่างที่คุณคงจำได้ เราทำงานกับพร็อกซีผ่านอินเทอร์เฟซ ไม่ใช่คลาส มีข้อกำหนดที่สำคัญ 2 ประการสำหรับอินเทอร์เฟซของเรา!
  1. ต้องขยายอินเทอร์เฟซระยะไกล
  2. ทุกเมธอดต้องโยน RemoteException (IDE จะไม่ทำสิ่งนี้โดยอัตโนมัติ คุณต้องเพิ่มสิ่งนี้ด้วยตนเอง!)
ตอนนี้เราต้องสร้างคลาสเซิร์ฟเวอร์ที่ใช้ อินเทอร์ เฟซ เครื่องคิดเลข ของเรา RMI ในทางปฏิบัติ - 2ที่นี่ทุกอย่างค่อนข้างง่าย:

import java.rmi.RemoteException;

public class RemoteCalculationServer implements Calculator {

   @Override
   public int multiply(int x, int y) throws RemoteException {
       return x*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);

   }
}
ลองคิดดูสิ :) ในบรรทัดแรก เราประกาศตัวแปร String บางตัว:

public static final String UNIQUE_BINDING_NAME = "server.calculator";
สตริงนี้เป็นชื่อเฉพาะของวัตถุระยะไกล โปรแกรมลูกค้าของเราใช้ชื่อนี้เพื่อค้นหาเซิร์ฟเวอร์ของเรา คุณจะเห็นชื่อนี้ในภายหลัง ต่อไป เราสร้างวัตถุเครื่องคิดเลขของเรา:

final RemoteCalculationServer server = new RemoteCalculationServer();
ทุกอย่างชัดเจนที่นี่ สิ่งที่จะตามมาน่าสนใจยิ่งขึ้น:

final Registry registry = LocateRegistry.createRegistry(2732);
วัตถุ Registry นี้เป็นรีจิสทรีของวัตถุระยะไกล นี่คือวัตถุที่โปรแกรมอื่นสามารถเข้าถึงได้จากระยะไกล :) เราส่งหมายเลข 2732 ไปยังเมธอดLocateRegistry.createRegistry() นี่คือหมายเลขพอร์ต — หมายเลขเฉพาะที่โปรแกรมอื่นๆ จะใช้เพื่อค้นหารีจิสทรีวัตถุของเรา (คุณจะเห็นอีกครั้งด้านล่าง) เดินหน้าต่อไป... มาดูกันว่าจะเกิดอะไรขึ้นในบรรทัดถัดไป:

Remote stub = UnicastRemoteObject.exportObject(server, 0);
เราสร้างต้นขั้วในบรรทัดนี้ ต้นขั้วสรุปการโทรระยะไกลทั้งหมด คุณสามารถถือว่าสิ่งนี้เป็นองค์ประกอบที่สำคัญที่สุดของ RMI มันทำอะไร?
  1. ได้รับข้อมูลทั้งหมดเกี่ยวกับการโทรระยะไกลของวิธีการบางอย่าง
  2. ถ้าเมธอดมีพารามิเตอร์ ต้นขั้วจะ deserialize ค่าเหล่านั้น ให้ความสนใจกับประเด็นนี้! อาร์กิวเมนต์ที่คุณส่งผ่านไปยังเมธอดที่เรียกจากระยะไกลจะต้องทำให้เป็นอนุกรมได้ (ท้ายที่สุดแล้วอาร์กิวเมนต์จะถูกส่งผ่านเครือข่าย) นี่ไม่ใช่ปัญหาสำหรับเรา เราแค่ส่งหมายเลข แต่ถ้าคุณกำลังส่งวัตถุ อย่าลืมข้อกำหนดนี้!
  3. หลังจากนั้นต้นขั้วก็เรียกเมธอดที่ต้องการ
เราส่งวัตถุเซิร์ฟเวอร์เครื่องคิดเลขของเราไปยังเมธอดUnicastRemoteObject.exportObject () นี่คือวิธีที่เราทำให้สามารถเรียกใช้เมธอดจากระยะไกลได้ เหลือเพียงสิ่งเดียวที่ต้องทำ:

registry.bind(UNIQUE_BINDING_NAME, stub);
เรา "ลงทะเบียน" ต้นขั้วของเราในรีจิสตรีวัตถุระยะไกลภายใต้ชื่อที่เราตั้งขึ้นเมื่อเริ่มต้น ตอนนี้ลูกค้าจะสามารถค้นหามันได้! บางทีคุณอาจสังเกตเห็นว่าเราทำให้เธรดหลักของโปรแกรมเข้าสู่โหมดสลีปในตอนท้าย:

Thread.sleep(Integer.MAX_VALUE);
เราเพียงแค่ต้องการให้เซิร์ฟเวอร์ทำงานเป็นเวลานาน ใน IDE เราจะเปิดตัวเมธอดmain() สอง เมธอดพร้อมกัน: วิธีแรก เมธอด main() ของเซิร์ฟเวอร์ (ใน คลาส ServerMainซึ่งเราได้เขียนไว้แล้ว) และวิธีที่สอง เมธอด main() ของลูกค้า (ในคลาสClientMainที่เราจะเขียนไว้ด้านล่าง) เป็นสิ่งสำคัญที่โปรแกรมเซิร์ฟเวอร์จะไม่ถูกยกเลิกในขณะที่เราเริ่มต้นไคลเอนต์ ดังนั้นเราเพียงแค่ปล่อยให้มันเข้าสู่โหมดสลีปเป็นเวลานาน ไม่ว่าในกรณีใด ๆ มันจะทำงานต่อไป :) ตอนนี้เราสามารถเรียกใช้เมธอดmain() ของเซิร์ฟเวอร์ของเราได้แล้ว ปล่อยให้มันทำงานและรอให้โปรแกรมไคลเอนต์เรียกใช้เมธอด :) ตอนนี้มาเขียนโปรแกรมไคลเอนต์กันเถอะ! มันจะส่งตัวเลขมาที่เซิร์ฟเวอร์ของเราเพื่อทำการคูณ

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);
   }
}
มันดูเรียบง่าย แต่เกิดอะไรขึ้นที่นี่? ขั้นแรก ไคลเอ็นต์ต้องทราบชื่อเฉพาะของวัตถุซึ่งเมธอดจะเรียกใช้จากระยะไกล ดังนั้น ในโปรแกรมไคลเอ็นต์ เราได้สร้างสตริงสุดท้ายแบบคงที่สาธารณะ UNIQUE_BINDING_NAME = "server.calculator"; ตัวแปร. ต่อไปใน เมธอด main()เราสามารถเข้าถึงรีจิสเตอร์ของวัตถุระยะไกลได้ ในการทำเช่นนี้ เราจำเป็นต้องเรียกใช้เมธอดLocateRegistry.getRegistry()และส่งผ่านหมายเลขพอร์ตที่ใช้สร้างรีจิสทรีของเราในโปรแกรม ServerMain (พอร์ต 2732 หมายเลขนี้เป็นเพียงตัวอย่างเท่านั้น คุณสามารถลองใช้หมายเลขอื่นได้):

final Registry registry = LocateRegistry.getRegistry(2732);
ตอนนี้เราต้องได้รับวัตถุที่ต้องการจากรีจิสทรี! ง่ายเพราะเรารู้ชื่อเฉพาะของมัน!

Calculator calculator = (Calculator) registry.lookup(UNIQUE_BINDING_NAME);
ให้ความสนใจกับการหล่อแบบ เราส่งวัตถุที่ได้รับไปยัง อินเทอร์เฟซ เครื่องคิดเลขไม่ใช่คลาสRemoteCalculationServer ดังที่เรากล่าวไว้ในตอนต้นของบทเรียน RMI อาศัยพร็อกซี ดังนั้นการโทรระยะไกลจึงใช้ได้เฉพาะกับวิธีการของอินเทอร์เฟซเท่านั้น ไม่ใช่วิธีการของชั้นเรียน สุดท้าย เราเรียกใช้ เมธอด multiply()บนวัตถุของเราจากระยะไกลและส่งออกผลลัพธ์ไปยังคอนโซล

int multiplyResult = calculator.multiply(20, 30);
System.out.println(multiplyResult);
เมธอดmain()ของคลาสServerMainได้ทำงานมานานแล้ว ตอนนี้ได้เวลาเรียกใช้ เมธอด main()ในโปรแกรมไคลเอนต์ ( ClientMain ) แล้ว! เอาต์พุตคอนโซล:

600
แค่นั้นแหละ! โปรแกรมของเรา (จริง ๆ แล้วมี 2 โปรแกรม!) ทำในสิ่งที่ควรจะทำ :) หากคุณมีเวลาและความปรารถนา คุณสามารถเพิ่มสีสันให้กับสิ่งนี้ได้เล็กน้อย ตัวอย่างเช่น ทำให้เครื่องคิดเลขรองรับการดำเนินการเลขคณิตมาตรฐานสี่รายการ และส่งผ่านตัวเลขที่ไม่ใช่ประเภทดั้งเดิม แต่เป็นวัตถุCalculationInstance(int x, int y) พบกันใหม่บทเรียนหน้า! :)
ความคิดเห็น
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION