JavaRush /Блоги Java /Random-TG /Проксиҳои динамикӣ дар Java

Проксиҳои динамикӣ дар Java

Дар гурӯҳ нашр шудааст
Салом! Имрӯз мо як мавзӯи хеле муҳим ва ҷолибро баррасӣ хоҳем кард - эҷоди синфҳои прокси динамикӣ дар Java. Ин хеле содда нест, пас биёед кӯшиш кунем, ки онро бо мисолҳо муайян кунем :) Пас, саволи муҳимтарин: проксиҳои динамикӣ чист ва онҳо барои чӣ кор мекунанд? Синфи прокси як навъ "суперструктураи" болои синфи аслӣ мебошад, ки ба мо имкон медиҳад, ки дар ҳолати зарурӣ рафтори онро тағир диҳем. Тағйир додани рафтор чӣ маъно дорад ва он чӣ гуна кор мекунад? Биёед як мисоли оддиро дида бароем. Фарз мекунем, ки мо интерфейс 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);
   }

   //..геттеры, сеттеры, и т.д.
}
Синфи мо Man3 усул дорад: худро муаррифӣ кунед, синну солатонро бигӯед ва аз куҷо буданатонро гӯед. Биёед тасаввур кунем, ки мо ин синфро ҳамчун як қисми китобхонаи омодаи JAR гирифтаем ва наметавонем codeи онро бигирем ва аз нав нависем. Бо вуҷуди ин, мо бояд рафтори ӯро тағир диҳем. Масалан, мо намедонем, ки кадом усул ба an objectи мо даъват карда мешавад ва аз ин рӯ мо мехоҳем, ки шахс ҳангоми занг задан ба яке аз онҳо аввал “Салом!” бигӯяд. (касе беадабро дӯст намедорад). Проксиҳои динамикӣ - 1Дар чунин вазъият мо бояд чӣ кор кунем? Мо ба чанд чиз ниёз дорем:
  1. InvocationHandler

Ин чист? Онро метавон айнан ҳамчун "монеъкунандаи занг" тарҷума кард. Ин ҳадафи онро хеле дақиқ тавсиф мекунад. InvocationHandlerинтерфейси махсусест, ки ба мо имкон медиҳад, ки ҳама гуна зангҳои методиро ба an objectи худ боздорем ва рафтори иловагиеро, ки ба мо лозим аст, илова кунем. Мо бояд интерсептори худамонро созем - яъне синф эҷод кунем ва ин интерфейсро амалӣ кунем. Ин хеле содда аст:
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(). Он, воқеан, он чизеро, ки ба мо лозим аст, иҷро мекунад - он ҳама зангҳои методиро ба an objectи мо халалдор мекунад ва рафтори заруриро илова мекунад (дар ин ҷо мо invoke()“Салом!” -ро ба консол дар дохor усул чоп мекунем).
  1. Объекти аслӣ ва прокси он.
Биёед an objectи аслӣ 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());

   }
}
Он қадар оддӣ ба назар намерасад! Ман махсусан барои ҳар як сатри code шарҳ навиштам: биёед бодиққат ба он чизе ки дар он ҷо рӯй дода истодааст, бубинем.

Дар сатри аввал мо танҳо an objectи аслиро месозем, ки барои он прокси эҷод мекунем. Ду сатри зерин метавонад боиси нофаҳмиҳо гардад:
//Получаем загрузчик класса у оригинального an object
ClassLoader vasiaClassLoader = vasia.getClass().getClassLoader();

//Получаем все интерфейсы, которые реализует оригинальный an object
Class[] interfaces = vasia.getClass().getInterfaces();
Аммо дар ин ҷо воқеан ягон чизи махсусе нест :) Барои сохтани прокси ба мо ClassLoader(боркунаки синф)-и an objectи аслӣ ва рӯйхати ҳамаи интерфейсҳое лозим аст, ки синфи аслии мо (яъне Man) амалӣ мекунад. Агар шумо намедонед, ки ин чист ClassLoader, шумо метавонед ин мақоларо дар бораи боркунии дарсҳо ба JVM ё ин дар Habré хонед , аммо ҳоло бо он зиёд ташвиш надиҳед. Танҳо дар хотир доред, ки мо маълумоти каме иловагӣ мегирем, ки мо бояд an objectи проксиро эҷод кунем. Дар сатри чорум мо синфи махсус Proxyва усули статикии онро истифода мебарем newProxyInstance():
//Создаем прокси нашего an object vasia
Person proxyVasia = (Person) Proxy.newProxyInstance(vasiaClassLoader, interfaces, new PersonInvocationHandler(vasia));
Ин усул танҳо an objectи прокси моро эҷод мекунад. Ба усул мо маълумотро дар бораи синфи аслӣ, ки дар қадами қаблӣ гирифта будем (он ClassLoaderва рӯйхати интерфейсҳои он), инчунин an objectи интерсепторе, ки мо қаблан офаридаем - InvocationHandler'a. Чизи асосӣ ин аст, ки фаромӯш накунед, ки an objectи аслии моро ба interceptor гузаронед vasia, вагарна он чизе барои "монеъ шудан" надорад :) Мо бо чӣ анҷом ёфтем? Ҳоло мо an objectи прокси дорем vasiaProxy. Он метавонад ҳама гуна усулҳои интерфейсроPerson даъват кунад . Чаро? Азбаски мо ба он рӯйхати ҳамаи интерфейсҳоро додем - дар ин ҷо:
//Получаем все интерфейсы, которые реализует оригинальный an object
Class[] interfaces = vasia.getClass().getInterfaces();

//Создаем прокси нашего an object vasia
Person proxyVasia = (Person) Proxy.newProxyInstance(vasiaClassLoader, interfaces, new PersonInvocationHandler(vasia));
Ҳоло ӯ аз ҳама усулҳои интерфейс "хабар аст" Person. Илова бар ин, мо ба прокси худ an objectеро гузаштем PersonInvocationHandler, ки барои кор бо an object танзим шудааст vasia:
//Создаем прокси нашего an object vasia
Person proxyVasia = (Person) Proxy.newProxyInstance(vasiaClassLoader, interfaces, new PersonInvocationHandler(vasia));
Ҳоло, агар мо ягон усули интерфейсро дар an objectи прокси даъват кунем 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());
бояд ба консол баромад кунад "Салом! Номи ман Вася аст, на танҳо "Салом!" Чӣ тавр мо ба ин ноил шуда метавонем? Ҳеҷ чизи мураккаб нест: шумо бояд каме бо интерсептор ва усули мо кор кунед invoke():) Ба он диққат диҳед, ки кадом далелҳо ба ин усул дода мешаванд:
public Object invoke(Object proxy, Method method, Object[] args)
Метод invoke()ба усуле, ки ба ҷои он номида мешавад ва ҳамаи аргументҳои он дастрасӣ дорад (метод, Object [] args). Ба ибораи дигар, агар мо методро даъват кунем proxyVasia.introduce(vasia.getName())ва ба ҷои метод методе introduce()номида шавад invoke(), дар дохor он метод мо ҳам ба усули аслӣ 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()Ҳоло мо зангро ба усули аслӣ ба усул илова кардем . Агар мо ҳоло кӯшиш кунем, ки codeро аз мисоли пешинаи худ иҷро кунем:
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 усул чек илова кунед, то бубинед, ки корбар логин ва паролро ворид кардааст, бе такрори рамзи тасдиқ дар ҳар як усул алоҳида. Ё, масалан, агар шумо хоҳед, ки гузорише эҷод кунед, ки дар он тамоми амалҳои корбар сабт карда мешаванд, ин корро бо истифода аз прокси низ осон аст. Шумо ҳатто ҳоло метавонед: танҳо codeро ба мисол илова кунед, то ҳангоми занг задан номи метод дар консол нишон дода шавад invoke()ва шумо як сабти оддии барномаи моро мегиред :) Дар охири лексия ба як муҳим диққат диҳед . маҳдудият . Эҷоди an objectи прокси дар сатҳи интерфейс сурат мегирад, на дар сатҳи синф. Барои интерфейс прокси сохта шудааст. Ба ин code нигаред:
//Создаем прокси нашего 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 наметавонад ба Man интиқол дода шавад Мавҷудияти интерфейс як талаботи ҳатмист. Прокси дар сатҳи интерфейс кор мекунад. Ин ҳама барои имрӯз аст :) Ҳамчун маводи иловагӣ дар мавзӯи прокси, ман метавонам ба шумо як видеои аъло ва инчунин мақолаи хубро. Хуб, ҳоло чанд масъаларо ҳал кардан хуб мешуд! :) То дидор!
Шарҳҳо
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION