JavaRush /جاوا بلاگ /Random-SD /جاوا ۾ متحرڪ پراڪس

جاوا ۾ متحرڪ پراڪس

گروپ ۾ شايع ٿيل
سلام! اڄ اسان هڪ اهم ۽ دلچسپ موضوع تي نظر ڪنداسين - جاوا ۾ متحرڪ پراکسي ڪلاس ٺاهڻ. اهو تمام سادو ناهي، تنهنڪري اچو ته ان کي مثالن سان سمجهڻ جي ڪوشش ڪريو :) تنهن ڪري، سڀ کان اهم سوال: متحرڪ پراکسي ڇا آهن ۽ اهي ڇا لاء آهن؟ هڪ پراڪسي ڪلاس اصل طبقي جي مٿان هڪ قسم جو ”سپر اسٽرڪچر“ آهي، جيڪو اسان کي اجازت ڏئي ٿو ته جيڪڏهن ضرورت هجي ته ان جي رويي کي تبديل ڪري سگهون. رويي کي تبديل ڪرڻ جو ڇا مطلب آهي ۽ اهو ڪيئن ڪم ڪري ٿو؟ اچو ته هڪ سادي مثال تي نظر. اچو ته اسان وٽ هڪ انٽرفيس آهي Person۽ هڪ سادي ڪلاس آهي Manجيڪو هن انٽرفيس کي لاڳو ڪري ٿو
public interface Person {

   public void introduce(String name);

   public void sayAge(int age);

   public void sayFrom(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("Меня зовут " + this.name);
   }

   @Override
   public void sayAge(int age) {
       System.out.println("Мне " + this.age + " years");
   }

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

       System.out.println("Я из города " + this.city + ", " + this.country);
   }

   //..геттеры, сеттеры, и т.д.
}
اسان جي ڪلاس Manجا 3 طريقا آھن: پنھنجو تعارف ڪرايو، پنھنجي عمر چئو، ۽ چئو ته توھان ڪٿي آھيو. اچو ته تصور ڪريون ته اسان هي ڪلاس هڪ تيار ڪيل JAR لائبريري جي حصي طور حاصل ڪيو آهي ۽ صرف ان جو ڪوڊ وٺي ۽ ٻيهر نه ٿا ڪري سگهون. تنهن هوندي، اسان کي هن جي رويي کي تبديل ڪرڻ جي ضرورت آهي. مثال طور، اسان کي خبر ناهي ته ڪهڙي طريقي سان اسان جي اعتراض تي سڏيو ويندو، ۽ تنهنڪري اسان چاهيون ٿا ته ماڻهو پهريون ڀيرو چوندا آهن "هيلو!" جڏهن انهن مان ڪنهن کي سڏيندو. (ڪو به ڪنهن کي پسند نٿو ڪري جيڪو بيوقوف آهي). متحرڪ پراکسيز - 1اهڙي صورتحال ۾ اسان کي ڇا ڪرڻ گهرجي؟ اسان کي ڪجھ شين جي ضرورت پوندي:
  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("Hello!");
       return null;
   }
}
اسان کي صرف هڪ انٽرفيس طريقو لاڳو ڪرڻ جي ضرورت آهي - invoke(). اهو، حقيقت ۾، اهو ڪري ٿو جيڪو اسان کي گهربل آهي - اهو اسان جي اعتراض کي سڀني طريقن جي ڪالن کي روڪي ٿو ۽ ضروري رويي کي شامل ڪري ٿو (هتي اسان invoke()"هيلو!" پرنٽ ڪندا آهيون طريقي جي اندر ڪنسول ڏانهن).
  1. اصل اعتراض ۽ ان جو پراڪس.
اچو ته Manان لاءِ هڪ اصل شئي ۽ هڪ ”سپر اسٽريچر“ (پراڪسي) ٺاهيون:
import java.lang.reflect.Proxy;

public class Main {

   public static void main(String[] args) {

       //Создаем оригинальный an object
       Man vasia = new Man("Vasya", 30, "Санкт-Петербург", "Россия");

       //Получаем загрузчик класса у оригинального an object
       ClassLoader vasiaClassLoader = vasia.getClass().getClassLoader();

       //Получаем все интерфейсы, которые реализует оригинальный an object
       Class[] interfaces = vasia.getClass().getInterfaces();

       //Создаем прокси нашего an object vasia
       Person proxyVasia = (Person) Proxy.newProxyInstance(vasiaClassLoader, interfaces, new PersonInvocationHandler(vasia));

       //Вызываем у прокси an object один из методов нашего оригинального an object
       proxyVasia.introduce(vasia.getName());

   }
}
بلڪل سادو نه ٿو لڳي! مون خاص طور تي ڪوڊ جي هر لڪير لاءِ هڪ تبصرو لکيو: اچو ته هڪ ويجهي نظر وجهون ته اتي ڇا ٿي رهيو آهي.

پهرين لائن ۾ اسان صرف اصل شئي ٺاهيندا آهيون جنهن لاءِ اسان هڪ پراڪسي ٺاهينداسين. هيٺيون ٻه لائينون شايد توهان کي مونجهاري جو سبب بڻائين:
//Получаем загрузчик класса у оригинального an object
ClassLoader vasiaClassLoader = vasia.getClass().getClassLoader();

//Получаем все интерфейсы, которые реализует оригинальный an object
Class[] interfaces = vasia.getClass().getInterfaces();
پر هتي واقعي ڪا خاص ڳالهه ناهي:) هڪ پراڪسي ٺاهڻ لاءِ، اسان کي ClassLoaderاصل شئي جي (ڪلاس لوڊر) جي ضرورت آهي ۽ انهن سڀني انٽرفيس جي فهرست جي ضرورت آهي جيڪي اسان جو اصل ڪلاس (يعني Man) لاڳو ڪري ٿو. جيڪڏهن توهان کي خبر ناهي ته اهو ڇا آهي ClassLoader، توهان پڙهي سگهو ٿا هي مضمون JVM ۾ ڪلاس لوڊ ڪرڻ بابت يا هي هڪ Habré تي ، پر اڃا تائين ان سان تمام گهڻو پريشان نه ڪريو. بس ياد رکو ته اسان ٿوري اضافي معلومات حاصل ڪري رهيا آهيون ته پوء اسان کي پراکسي اعتراض ٺاهڻ جي ضرورت پوندي. چوٿين لڪير تي اسان هڪ خاص ڪلاس Proxy۽ ان جو جامد طريقو استعمال ڪريون ٿا newProxyInstance():
//Создаем прокси нашего an object vasia
Person proxyVasia = (Person) Proxy.newProxyInstance(vasiaClassLoader, interfaces, new PersonInvocationHandler(vasia));
اهو طريقو صرف اسان جي پراکسي اعتراض ٺاهي ٿو. طريقي سان اسان اصل ڪلاس بابت معلومات پاس ڪندا آهيون جيڪا اسان اڳئين مرحلي ۾ حاصل ڪئي هئي (اهو ClassLoader۽ ان جي انٽرفيس جي فهرست)، انهي سان گڏ انٽرسيپٽر جو اعتراض جيڪو اسان اڳ ۾ ٺاهيو هو - InvocationHandler'a. مکيه شيء آهي ته اسان جي اصلي اعتراض کي مداخلت ڪندڙ ڏانهن منتقل ڪرڻ نه وساريو vasia، ٻي صورت ۾ ان کي "Intercept" ڪرڻ لاء ڪجھ به نه هوندو :) اسان آخر ڇا ڪيو؟ اسان وٽ ھاڻي ھڪڙو پراکسي اعتراض آھي vasiaProxy. اهو ڪنهن به انٽرفيس طريقن کيPerson سڏي سگهي ٿو . ڇو؟ ڇاڪاڻ ته اسان ان کي منظور ڪيو سڀني انٽرفيس جي هڪ فهرست - هتي:
//Получаем все интерфейсы, которые реализует оригинальный an object
Class[] interfaces = vasia.getClass().getInterfaces();

//Создаем прокси нашего an object vasia
Person proxyVasia = (Person) Proxy.newProxyInstance(vasiaClassLoader, interfaces, new PersonInvocationHandler(vasia));
هاڻي هو سڀني انٽرفيس طريقن کان "آگاهه" آهي Person. ان کان علاوه، اسان اسان جي پراڪس کي منظور ڪيو هڪ PersonInvocationHandlerاعتراض سان ڪم ڪرڻ لاء ترتيب ڏنل vasia:
//Создаем прокси нашего an object vasia
Person proxyVasia = (Person) Proxy.newProxyInstance(vasiaClassLoader, interfaces, new PersonInvocationHandler(vasia));
هاڻي، جيڪڏهن اسان پراکسي اعتراض تي ڪنهن به انٽرفيس طريقي کي سڏيندا آهيون Person، اسان جو مداخلت ڪندڙ هن ڪال کي "پڪڙندو" ۽ ان جي بدران ان جي پنهنجي طريقي تي عمل ڪندو invoke(). اچو ته طريقي سان هلائڻ جي ڪوشش ڪريو main()! ڪنسول آئوٽ: هيلو! زبردست! اسان ڏسون ٿا ته حقيقي طريقي جي بدران، اسان جو Person.introduce()طريقو سڏيو ويندو آهي : invoke()PersonInvocationHandler()
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

   System.out.println("Hello!");
   return null;
}
۽ ڪنسول ظاهر ڪيو "هيلو!" پر اهو بلڪل اهڙو رويو ناهي جيڪو اسان حاصل ڪرڻ چاهيون ٿا:/ اسان جي خيال موجب، ”هيلو!“ پهرين ظاهر ٿيڻ گهرجي، ۽ پوءِ اهو طريقو جيڪو اسان سڏي رهيا آهيون، ڪم ڪرڻ گهرجي. ٻين لفظن ۾، هي طريقو سڏي ٿو:
proxyVasia.introduce(vasia.getName());
ڪنسول ڏانهن آئوٽ ٿيڻ گهرجي ”هيلو! منهنجو نالو Vasya آهي، ۽ نه رڳو "هيلو!" اسان اهو ڪيئن حاصل ڪري سگهون ٿا؟ ڪجھ به پيچيده نه آهي: توهان کي صرف اسان جي مداخلت ڪندڙ ۽ طريقي سان ٿورڙي ٽينڪر ڪرڻو پوندو invoke():) ڌيان ڏيو ته هن طريقي سان ڪهڙا دليل منظور ڪيا ويا آهن:
public Object invoke(Object proxy, Method method, Object[] args)
هڪ طريقو invoke()کي طريقي تائين رسائي آهي ان کي بدران سڏيو ويندو آهي ۽ ان جا سڀئي دليل (طريقي طريقو، Object[] args). ٻين لفظن ۾، جيڪڏهن اسان هڪ طريقي کي سڏيندا آهيون proxyVasia.introduce(vasia.getName())، ۽ هڪ طريقي جي بدران ، introduce()هڪ طريقو سڏيو ويندو آهي invoke()، ان طريقي جي اندر اسان کي اصل طريقو introduce()۽ ان جي دليل ٻنهي تائين رسائي آهي! نتيجي طور، اسان هن طرح ڪجهه ڪري سگهون ٿا:
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("Hello!");
       return method.invoke(person, args);
   }
}
ھاڻي اسان invoke()ھڪڙي ڪال کي شامل ڪيو آھي اصل طريقي سان طريقي سان. جيڪڏهن اسان هاڻي اسان جي پوئين مثال مان ڪوڊ هلائڻ جي ڪوشش ڪريون ٿا:
import java.lang.reflect.Proxy;

public class Main {

   public static void main(String[] args) {

       //Создаем оригинальный an object
       Man vasia = new Man("Vasya", 30, "Санкт-Петербург", "Россия");

       //Получаем загрузчик класса у оригинального an object
       ClassLoader vasiaClassLoader = vasia.getClass().getClassLoader();

       //Получаем все интерфейсы, которые реализует оригинальный an object
       Class[] interfaces = vasia.getClass().getInterfaces();

       //Создаем прокси нашего an object vasia
       Person proxyVasia = (Person) Proxy.newProxyInstance(vasiaClassLoader, interfaces, new PersonInvocationHandler(vasia));

       //Вызываем у прокси an object один из методов нашего оригинального an object
       proxyVasia.introduce(vasia.getName());
   }
}
پوءِ اسان ڏسنداسين ته هاڻي هر شي ڪم ڪري ٿي جيئن ان کي گهرجي :) ڪنسول آئوٽ: هيلو! منهنجو نالو واسيا آهي، توهان کي ڪٿي ضرورت پئجي سگهي ٿي؟ حقيقت ۾، ڪيترن ئي هنڌن تي. ”متحرڪ پراکسي“ ڊيزائن جو نمونو فعال طور تي مشهور ٽيڪنالاجيز ۾ استعمال ٿيندو آهي... ۽ رستي ۾، مان توهان کي ٻڌائڻ وساري ويس ته Dynamic Proxyاهو هڪ نمونو آهي ! مبارڪون، توهان هڪ ٻيو سکيو آهي! :) متحرڪ پراکسيز - 2تنهن ڪري، اهو فعال طور تي مشهور ٽيڪنالاجيز ۽ سيڪيورٽي سان لاڳاپيل فريم ورڪ ۾ استعمال ٿيندو آهي. تصور ڪريو ته توھان وٽ 20 طريقا آھن جيڪي صرف توھان جي پروگرام جي لاگ ان ٿيل استعمال ڪندڙن پاران عمل ڪري سگھجن ٿيون. استعمال ڪندي جيڪي توهان سکيا آهن، توهان آساني سان انهن 20 طريقن ۾ هڪ چيڪ شامل ڪري سگهو ٿا ته ڇا صارف لاگ ان ۽ پاسورڊ داخل ڪيو آهي، بغير تصديق ڪوڊ کي هر طريقي سان الڳ ڪرڻ جي. يا، مثال طور، جيڪڏهن توهان هڪ لاگ ٺاهڻ چاهيو ٿا جتي صارف جا سڀئي عمل رڪارڊ ڪيا ويندا، اهو پڻ آسان آهي پراڪسي استعمال ڪندي. توھان ھاڻي به ڪري سگھو ٿا: مثال ۾ صرف ڪوڊ شامل ڪريو ته جيئن توھان کي سڏيو وڃي ته طريقي جو نالو ڪنسول ۾ ڏيکاريل آھي invoke()، ۽ توھان کي اسان جي پروگرام جو ھڪڙو سادو لاگ ملندو :) ليڪچر جي آخر ۾، ھڪڙي اھم ڏانھن ڌيان ڏيو. حد بندي پراکسي شئي ٺاهڻ انٽرفيس جي سطح تي ٿئي ٿي، نه ڪلاس جي سطح تي. انٽرفيس لاءِ هڪ پراڪسي ٺاهي وئي آهي. هن ڪوڊ تي هڪ نظر وٺو:
//Создаем прокси нашего an object vasia
Person proxyVasia = (Person) Proxy.newProxyInstance(vasiaClassLoader, interfaces, new PersonInvocationHandler(vasia));
هتي اسان خاص طور تي انٽرفيس لاءِ هڪ پراڪسي ٺاهيندا آهيون Person. جيڪڏهن اسان ڪلاس لاءِ پراڪسي ٺاهڻ جي ڪوشش ڪريون ٿا، يعني اسان لنڪ جو قسم تبديل ڪري ڪلاس ۾ ڪاسٽ ڪرڻ جي ڪوشش ڪريون ٿا Man، ڪجھ به ڪم نه ڪندو.
Man proxyVasia = (Man) Proxy.newProxyInstance(vasiaClassLoader, interfaces, new PersonInvocationHandler(vasia));

proxyVasia.introduce(vasia.getName());
ٿريڊ ۾ استثنا "main" java.lang.ClassCastException: com.sun.proxy.$Proxy0 انسان کي ڪاسٽ نه ٿو ڪري سگھجي، هڪ انٽرفيس جي موجودگي هڪ لازمي گهرج آهي. پراکسي انٽرفيس جي سطح تي ڪم ڪري ٿو. اهو سڀ ڪجهه اڄ جي لاءِ آهي :) پراڪسز جي موضوع تي اضافي مواد جي طور تي، مان توهان کي هڪ بهترين وڊيو ۽ پڻ سٺو مضمون جي سفارش ڪري سگهان ٿو . خير، هاڻي اهو سٺو لڳندو ته ڪجهه مسئلا حل ڪريو! :) ملندا سين!
تبصرا
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION