به نام خدا
بالاخره پس از یک هفته دور بودن از زندگی برنامه نویسی و تجربه کردن چهره های دیگر زندگی امروز به زندگی برنامه نویسی برگشتم، به قول یه فیلسوفی میگفت که در هر چیزی نکته ای یادگرفتنی وجود دارد و چه نکاتی که باید آموخت ...
امروز میخواهم راجع به یکی از نقاط قوت جاوا و همچنین یکی از علایق خودم به نام RMI بنویسیم.
RMI (Remote Method Invocation)
میتوان آنرا به فراخانی متد راه دور ترجمه کرد، یک رابط برنامه نویسی (API) در جاوا است که وظیفه آن فراخوانی یک متد در یک شی (Object) که در ماشین دیگری قرار دارد است، این یک تعریف کلی بود و اگر بخواهیم جزئی تر به مطلب بپردازیم میتوانیم یک مدل کلاینت/سرور را در نظر بگیریم که در أن سرور ماشینی است که متد قابل فرخوانی در آن وجود دارد و کلاینت ماشینی است که متدی را از سرور فراخوانی میکند.
سرور - ماشینی است که وظیفه انجام دادن یک عمل (Task) را بر اساس یک درخواست دارد.
کلاینت - ماشینی است که درخواستی را به ماشین سرور میفرستد.
اگر شما میخواهید که یک متد را از یک کلاس فراخوانی کنید اولا باید بتوانید در ماشین سرور از آن کلاس یک شی بسازید ثانیا آن کلاس باید قابل دسترس باشد.
در RMI، کلاسی که قرار است متدی از آن فرخوانی بشود فقط و فقط در ماشین سرور وجود دارد و کلاینت قرار است که درخواستی به سرور بفرستد تا سرور آن کار را انجام دهد. برای این کار نیاز به RMI registry داریم.
RMI registry چیست : RMI registry را مانند یک کتاب در نظر بگیرید که در آن اشیا مورد نیاز کلاینتها از طرف سرورها با یک نام مشخص (که میتواند RMI url باشد) در آن ثبت شده است و کلاینتها میتوانند با استفاده از نام اشیا که در هنگام ثبت در RMI registry به آن اختصاص داده شده است، آن شی را از RMI registry فراخوانی میکنند.
اگر بخواهیم یک متدی داشته باشیم که بتوان این متد را فراخوانی کنیم باید این متد را در یک interface که از remote interface ارث برده است معرفی کنیم.
برای مثال :
import java.rmi.*; public interface NameCollections extends Remote //Remote Interface{ public String getName(int index)throws RemoteException;//Remotely Accessible Method }
و کلاسی که این ایترفیس را پیاده سازی میکند مانند زیر است :
import java.rmi.*; import java.util.*; import java.rmi.server.*; class NameStorage extends UnicastRemoteObject implements NameCollections { //A Class That Implements The Remote Interface private Map name; public NameStorage()throws RemoteException{ name=new HashMap(); name.put(1,"iman"); name.put(2,"reihanian"); } public String getName(int index)throws RemoteException{ String str=name.get(new Integer(index)); return str; }
در ادامه پیاده سازی RMI در سرور :
import java.rmi.*; import javax.naming.*; class NameServer { public static void main(String args[]) throws RemoteException,NamingException { Context ictxt=new InitialContext(); NameStorage store=new NameStorage(); ictxt.bind("rmi:Storage",store);//Binding The Remote Object(store) With A Name(storage) System.out.println("Clients can invoke the methods...."); } }
و در قسمت کلاینت :
import java.rmi.*; import java.util.*; import javax.naming.*; class NameClient { public static void main(String args[])throws NamingException,RemoteException { Context itxt=new InitialContext(); //Searching For The Remote Object In The RMI registry NameCollections coll= (NameCollections) itxt.lookup("rmi://localhost/Storage"); String n1=coll.getName(2);// Invoking The Remote Method System.out.println("Name Obtained from the server:" + n1); } }
اینطور به نظر میرسد که متد از سرور فراخوانی شده است در حالیکه فقط اینطور به نظر میرسد و واقعا اینطور نیست، کلاینت متدی را که در شی stub است فرخوانی کرده است و این شی stub متد سرور را فراخوانی کرده است و نتیجه را از سرور به کلاینت بر میگرداند.
stub چیست ؟ stub را میتوان به عنوان یک cache از اشیا remote در نظر گرفت که در کلاینت وجود دارند.
میتوان شکل کلی RMI را بصورت زیر رسم کرد :