CodeGym /جاوا بلاگ /Random-UR /جاوا میں متحرک پراکسی
John Squirrels
سطح
San Francisco

جاوا میں متحرک پراکسی

گروپ میں شائع ہوا۔
ہائے! آج ہم ایک اہم اور دلچسپ موضوع پر غور کریں گے: جاوا میں متحرک پراکسی کلاسز کی تخلیق۔ یہ بہت آسان نہیں ہے، لہذا ہم مثالوں کا استعمال کرتے ہوئے اس کا پتہ لگانے کی کوشش کریں گے :) تو، سب سے اہم سوال: متحرک پراکسیز کیا ہیں اور وہ کس کے لیے ہیں؟ ایک پراکسی کلاس اصل کلاس کے اوپر ایک قسم کی "ایڈ آن" ہے، جو ہمیں ضرورت پڑنے پر اصل کلاس کے رویے کو تبدیل کرنے کی اجازت دیتی ہے۔ "رویے کو تبدیل کرنے" کا کیا مطلب ہے اور یہ کیسے کام کرتا ہے؟ ایک سادہ مثال پر غور کریں۔ فرض کریں کہ ہمارے پاس پرسن انٹرفیس ہے اور ایک سادہ مین کلاس ہے جو اس انٹرفیس کو نافذ کرتی ہے۔
public interface Person {

   public void introduce(String name);

   public void sayAge(int age);

   public void sayWhereFrom(String city, String country);
}

public class Man implements Person {

   private String name;
   private int age;
   private String city;
   private String country;

   public Man(String name, int age, String city, String country) {
       this.name = name;
       this.age = age;
       this.city = city;
       this.country = country;
   }

   @Override
   public void introduce(String name) {

       System.out.println("My name is " + this.name);
   }

   @Override
   public void sayAge(int age) {
       System.out.println("I am " + this.age + " years old");
   }

   @Override
   public void sayWhereFrom(String city, String country) {

       System.out.println("I'm from " + this.city + ", " + this.country);
   }

   // ...getters, setters, etc.
}
ہماری مین کلاس کے 3 طریقے ہیں: متعارف کروائیں، عمر بتائیں، اور کہیں سے کہیں۔ تصور کریں کہ ہمیں یہ کلاس آف دی شیلف JAR لائبریری کے حصے کے طور پر ملی ہے اور ہم اس کے کوڈ کو دوبارہ نہیں لکھ سکتے۔ لیکن ہمیں اس کے رویے کو بھی بدلنے کی ضرورت ہے۔ مثال کے طور پر، ہم نہیں جانتے کہ ہمارے اعتراض پر کون سا طریقہ کہا جا سکتا ہے، لیکن ہم چاہتے ہیں کہ ہمارا شخص "ہیلو!" (کوئی بھی ایسے شخص کو پسند نہیں کرتا جو ناپاک ہو) جب کسی بھی طریقے کو پکارا جائے۔ متحرک پراکسیز - 2اس صورت حال میں ہمیں کیا کرنا چاہیے؟ ہمیں کچھ چیزوں کی ضرورت ہوگی:
  1. InvocationHandler

یہ کیا ہے؟ InvocationHandler ایک خاص انٹرفیس ہے جو ہمیں اپنے آبجیکٹ پر کسی بھی میتھڈ کال کو روکنے اور اضافی رویے کو شامل کرنے دیتا ہے۔ ہمیں اپنا انٹرسیپٹر بنانے کی ضرورت ہے، یعنی ایک کلاس بنائیں جو اس انٹرفیس کو نافذ کرے۔ یہ بہت آسان ہے:
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

public class PersonInvocationHandler implements InvocationHandler {

private Person person;

public PersonInvocationHandler(Person person) {
   this.person = person;
}

 @Override
   public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

       System.out.println("Hi!");
       return null;
   }
}
ہمیں صرف ایک انٹرفیس طریقہ کو نافذ کرنے کی ضرورت ہے: invoke() ۔ اور، ویسے، یہ وہی کرتا ہے جس کی ہمیں ضرورت ہوتی ہے: یہ ہمارے آبجیکٹ میں تمام میتھڈ کالز کو روکتا ہے اور ضروری رویے کا اضافہ کرتا ہے (invoke () طریقہ کے اندر، ہم "Hi!" کو کنسول میں آؤٹ پٹ کرتے ہیں)۔
  1. اصل اعتراض اور اس کی پراکسی۔
ہم اپنا اصل مین آبجیکٹ اور اس کے لیے ایک "ایڈ آن" (پراکسی) بناتے ہیں:
import java.lang.reflect.Proxy;

public class Main {

   public static void main(String[] args) {

       // Create the original object
       Man arnold = new Man("Arnold", 30, "Thal", "Austria");

       // Get the class loader from the original object
       ClassLoader arnoldClassLoader = arnold.getClass().getClassLoader();

       // Get all the interfaces that the original object implements
       Class[] interfaces = arnold.getClass().getInterfaces();

       // Create a proxy for our arnold object
       Person proxyArnold = (Person) Proxy.newProxyInstance(arnoldClassLoader, interfaces, new PersonInvocationHandler(arnold));

       // Call one of our original object's methods on the proxy object
       proxyArnold.introduce(arnold.getName());

   }
}
یہ بہت آسان نہیں لگتا! میں نے خاص طور پر کوڈ کی ہر سطر کے لیے ایک تبصرہ شامل کیا۔ چلو کیا ہو رہا ہے پر ایک قریبی نظر ڈالیں. پہلی لائن میں، ہم صرف اصل چیز بناتے ہیں جس کے لیے ہم پراکسی بنائیں گے۔ درج ذیل دو سطریں آپ کو دشواری کا باعث بن سکتی ہیں۔
// Get the class loader from the original object
ClassLoader arnoldClassLoader = arnold.getClass().getClassLoader();

// Get all the interfaces that the original object implements
Class[] interfaces = arnold.getClass().getInterfaces();
درحقیقت، یہاں کچھ خاص نہیں ہو رہا ہے :) چوتھی لائن میں، ہم خصوصی پراکسی کلاس اور اس کا جامد newProxyInstance() طریقہ استعمال کرتے ہیں:
// Create a proxy for our arnold object
Person proxyArnold = (Person) Proxy.newProxyInstance(arnoldClassLoader, interfaces, new PersonInvocationHandler(arnold));
یہ طریقہ صرف ہماری پراکسی آبجیکٹ بناتا ہے۔ ہم اصل کلاس کے بارے میں معلومات کو طریقہ پر منتقل کرتے ہیں، جو ہمیں آخری مرحلے میں موصول ہوئی تھی (اس کا ClassLoader اور اس کے انٹرفیس کی فہرست)، اور ساتھ ہی پہلے سے تخلیق کردہ InvocationHandler آبجیکٹ۔ اہم بات یہ ہے کہ ہم اپنے اصل آرنلڈ آبجیکٹ کو انووکیشن ہینڈلر کو منتقل کرنا نہ بھولیں، بصورت دیگر "ہینڈل" کرنے کے لیے کچھ نہیں ہوگا :) ہم نے آخر کیا کیا؟ ہمارے پاس اب ایک پراکسی آبجیکٹ ہے: proxyArnold ۔ یہ پرسن انٹرفیس کے کسی بھی طریقے کو کال کر سکتا ہے۔ کیوں؟ کیونکہ ہم نے اسے یہاں تمام انٹرفیس کی فہرست دی ہے۔
// Get all the interfaces that the original object implements
Class[] interfaces = arnold.getClass().getInterfaces();

// Create a proxy for our arnold object
Person proxyArnold = (Person) Proxy.newProxyInstance(arnoldClassLoader, interfaces, new PersonInvocationHandler(arnold));
اب یہ پرسن انٹرفیس کے تمام طریقوں کے بارے میں جانتا ہے ۔ اس کے علاوہ، ہم نے اپنی پراکسی کو ایک PersonInvocationHandler آبجیکٹ ارنلڈ آبجیکٹ کے ساتھ کام کرنے کے لیے کنفیگر کیا ہے:
// Create a proxy for our arnold object
Person proxyArnold = (Person) Proxy.newProxyInstance(arnoldClassLoader, interfaces, new PersonInvocationHandler(arnold));
اب اگر ہم پراکسی آبجیکٹ پر پرسن انٹرفیس کے کسی بھی طریقہ کو کال کرتے ہیں، تو ہمارا ہینڈلر کال کو روکتا ہے اور اس کے بجائے اس کا اپنا invoke() طریقہ کار انجام دیتا ہے۔ آئیے main() طریقہ کو چلانے کی کوشش کریں! کنسول آؤٹ پٹ:

Hi!
بہترین! ہم دیکھتے ہیں کہ اصل Person.introduce() طریقہ کے بجائے، ہمارے PersonInvocationHandler() کے invoke() طریقہ کو کہا جاتا ہے:
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

   System.out.println("Hi!");
   return null;
}
"ہیلو!" کنسول پر ظاہر ہوتا ہے، لیکن یہ بالکل وہی سلوک نہیں ہے جو ہم چاہتے تھے:/ جو ہم حاصل کرنے کی کوشش کر رہے تھے وہ ہے پہلے "Hi!" اور پھر اصل طریقہ کو ہی کال کریں۔ دوسرے لفظوں میں میتھڈ کال
proxyArnold.introduce(arnold.getName());
ظاہر ہونا چاہئے "ہائے! میرا نام آرنلڈ ہے"، نہ کہ صرف "ہائے!" ہم یہ کیسے حاصل کر سکتے ہیں؟ یہ پیچیدہ نہیں ہے: ہمیں صرف اپنے ہینڈلر اور invoke() طریقہ کے ساتھ کچھ آزادی حاصل کرنے کی ضرورت ہے :) اس بات پر توجہ دیں کہ اس طریقہ پر کون سے دلائل پاس کیے جاتے ہیں:
public Object invoke(Object proxy, Method method, Object[] args)
invoke () طریقہ کو اصل میں مدعو کیے گئے طریقہ تک رسائی حاصل ہے، اور اس کے تمام دلائل (طریقہ طریقہ، آبجیکٹ[] آرگس) تک۔ دوسرے لفظوں میں، اگر ہم proxyArnold.introduce(arnold.getName()) طریقہ کو کہتے ہیں تاکہ invoke() طریقہ کو متعارف () طریقہ کے بجائے کہا جائے ، تو اس طریقہ کے اندر ہمیں اصل تعارف () طریقہ تک رسائی حاصل ہے۔ اور اس کی دلیل! نتیجے کے طور پر، ہم یہ کر سکتے ہیں:
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

public class PersonInvocationHandler implements InvocationHandler {

   private Person person;

   public PersonInvocationHandler(Person person) {

       this.person = person;
   }

   @Override
   public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
       System.out.println("Hi!");
       return method.invoke(person, args);
   }
}
اب invoke() طریقہ میں ہم نے اصل طریقہ میں کال کا اضافہ کیا ہے۔ اگر اب ہم اپنی پچھلی مثال سے کوڈ چلانے کی کوشش کرتے ہیں:
import java.lang.reflect.Proxy;

public class Main {

   public static void main(String[] args) {

       // Create the original object
       Man arnold = new Man("Arnold", 30, "Thal", "Austria");

       // Get the class loader from the original object
       ClassLoader arnoldClassLoader = arnold.getClass().getClassLoader();

       // Get all the interfaces that the original object implements
       Class[] interfaces = arnold.getClass().getInterfaces();

       // Create a proxy for our arnold object
       Person proxyArnold = (Person) Proxy.newProxyInstance(arnoldClassLoader, interfaces, new PersonInvocationHandler(arnold));

       // Call one of our original object's methods on the proxy object
       proxyArnold.introduce(arnold.getName());
   }
}
پھر ہم دیکھیں گے کہ اب سب کچھ کام کرتا ہے جیسا کہ ہونا چاہئے :) کنسول آؤٹ پٹ:

Hi! My name is Arnold
آپ کو اس کی کب ضرورت ہو سکتی ہے؟ اصل میں، اکثر. "متحرک پراکسی" ڈیزائن پیٹرن کو مقبول ٹیکنالوجیز میں فعال طور پر استعمال کیا جاتا ہے... اوہ، ویسے، میں یہ بتانا بھول گیا کہ ڈائنامک پراکسی ایک ڈیزائن پیٹرن ہے! مبارک ہو، آپ نے ایک اور سیکھا! :) متحرک پراکسیز - 3مثال کے طور پر، یہ سیکیورٹی سے متعلق مشہور ٹیکنالوجیز اور فریم ورکس میں فعال طور پر استعمال ہوتا ہے۔ تصور کریں کہ آپ کے پاس 20 طریقے ہیں جو صرف ان صارفین کے ذریعہ کیے جائیں جو آپ کے پروگرام میں سائن ان ہیں۔ آپ نے جو تکنیکیں سیکھی ہیں ان کا استعمال کرتے ہوئے، آپ آسانی سے ان 20 طریقوں میں یہ چیک شامل کر سکتے ہیں کہ آیا صارف نے ہر طریقہ میں تصدیقی کوڈ کو نقل کیے بغیر درست اسناد داخل کی ہیں۔ یا فرض کریں کہ آپ ایک لاگ بنانا چاہتے ہیں جہاں صارف کے تمام اعمال ریکارڈ کیے جائیں گے۔ پراکسی کا استعمال کرتے ہوئے یہ کرنا بھی آسان ہے۔ اب بھی، آپ ہماری اوپر کی مثال میں آسانی سے کوڈ شامل کر سکتے ہیں تاکہ جب آپ invoke() کو کال کریں تو طریقہ کا نام ظاہر ہو ، اور یہ ہمارے پروگرام کا ایک انتہائی سادہ لاگ تیار کرے گا :) آخر میں، ایک اہم حد پر توجہ دیں۔ ایک پراکسی آبجیکٹ انٹرفیس کے ساتھ کام کرتا ہے، کلاسوں کے ساتھ نہیں۔ انٹرفیس کے لیے ایک پراکسی بنائی جاتی ہے۔ اس کوڈ پر ایک نظر ڈالیں:
// Create a proxy for our arnold object
Person proxyArnold = (Person) Proxy.newProxyInstance(arnoldClassLoader, interfaces, new PersonInvocationHandler(arnold));
یہاں ہم خاص طور پر پرسن انٹرفیس کے لیے ایک پراکسی بناتے ہیں ۔ اگر ہم کلاس کے لیے پراکسی بنانے کی کوشش کریں، یعنی ریفرنس کی قسم کو تبدیل کریں اور مین کلاس میں ڈالنے کی کوشش کریں، تو یہ کام نہیں کرے گا۔
Person proxyArnold = (Person) Proxy.newProxyInstance(arnoldClassLoader, interfaces, new PersonInvocationHandler(arnold));

proxyArnold.introduce(arnold.getName());
"main" تھریڈ میں استثنا java.lang.ClassCastException: com.sun.proxy.$Proxy0 انسان کو کاسٹ نہیں کیا جا سکتا انٹرفیس کا ہونا ایک مطلق ضرورت ہے۔ پراکسی انٹرفیس کے ساتھ کام کرتی ہیں۔ آج کے لیے بس اتنا ہی ہے :) اچھا، اب چند کاموں کو حل کر لیا جائے! :) اگلے وقت تک!
تبصرے
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION