CodeGym /Blog Jawa /Acak /Proxy Dinamis ing Jawa
John Squirrels
tingkat
San Francisco

Proxy Dinamis ing Jawa

Diterbitake ing grup
Hi! Dina iki kita bakal nimbang topik sing rada penting lan menarik: nggawe kelas proxy dinamis ing Jawa. Ora gampang banget, mula kita bakal nyoba ngerteni nggunakake conto :) Dadi, pitakonan sing paling penting: apa proxy dinamis lan kanggo apa? Kelas proxy minangka jinis "tambahan" ing ndhuwur kelas asli, sing ngidini kita ngganti prilaku kelas asli yen perlu. Apa tegese "ngganti prilaku" lan kepiye cara kerjane? Coba conto sing prasaja. Upaminipun kita duwe antarmuka Person lan kelas Man prasaja sing ngleksanakake antarmuka iki

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.
}
Kelas Man kita duwe 3 cara: introduce, sayAge, lan sayWhereFrom. Mbayangno yen kita entuk kelas iki minangka bagéan saka perpustakaan JAR sing ora bisa digunakake lan kita ora bisa nulis ulang kode kasebut. Nanging kita uga kudu ngganti prilaku. Contone, kita ora ngerti cara apa sing bisa diarani obyek kita, nanging kita pengin wong kita ngomong "Hai!" (ora ana sing seneng karo wong sing ora sopan) yen ana cara sing diarani. Proksi dinamis - 2Apa sing kudu kita lakoni ing kahanan iki? Kita butuh sawetara perkara:
  1. InvocationHandler

Apa iki? InvocationHandler minangka antarmuka khusus sing ngidini kita nyegat panggilan metode apa wae menyang obyek lan nambah prilaku tambahan sing dibutuhake. Kita kudu nggawe interceptor dhewe, yaiku nggawe kelas sing ngetrapake antarmuka iki. Iki cukup prasaja:

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;
   }
}
Kita kudu ngleksanakake mung siji cara antarmuka: invoke() . Lan, ing cara, iku apa kita kudu: intercepts kabeh cara telpon kanggo obyek lan nambah prilaku perlu (nang cara invoke () , kita output "Hi!" kanggo console).
  1. Objek asli lan proxy.
Kita nggawe obyek Man asli lan "add-on" (proxy) kanggo:

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());

   }
}
Iki ora katon banget prasaja! Aku khusus nambah komentar kanggo saben baris kode. Ayo dideleng kanthi cetha apa sing kedadeyan. Ing baris pisanan, kita mung nggawe obyek asli sing bakal nggawe proxy. Rong baris ing ngisor iki bisa nyebabake sampeyan angel:

 // 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();
Bener, ora ana sing khusus kedadeyan ing kene :) Ing baris kaping papat, kita nggunakake kelas Proxy khusus lan metode newProxyInstance() statis :

// Create a proxy for our arnold object
Person proxyArnold = (Person) Proxy.newProxyInstance(arnoldClassLoader, interfaces, new PersonInvocationHandler(arnold));
Cara iki mung nggawe obyek proxy kita. We pass menyang cara informasi bab kelas asli, kang ditampa ing langkah pungkasan ( ClassLoader lan dhaptar antarmuka sawijining), uga obyek InvocationHandler digawe sadurunge . Wangsulan: Bab ingkang utama iku ora lali kanggo pass arnold obyek asli kita kanggo handler invocation, yen ora bakal ana apa-apa kanggo "nangani" :) Apa kita mungkasi munggah karo? Saiki kita duwe obyek proxy: proxyArnold . Bisa nelpon sembarang cara saka antarmuka Person . Kenging punapa? Amarga kita menehi dhaptar kabeh antarmuka ing kene:

// 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));
Saiki ngerti babagan kabeh cara antarmuka Person . Kajaba iku, kita ngirim obyek PersonInvocationHandler menyang proxy sing dikonfigurasi kanggo nggarap obyek arnold :

// Create a proxy for our arnold object
Person proxyArnold = (Person) Proxy.newProxyInstance(arnoldClassLoader, interfaces, new PersonInvocationHandler(arnold));
Saiki yen kita nelpon sembarang cara saka antarmuka Person ing obyek proxy, handler kita intercepts telpon lan nglakokaké invoke dhewe () cara tinimbang. Ayo dadi nyoba kanggo mbukak cara utama () ! Output konsol:

Hi!
Banget! We ndeleng sing tinimbang Person.introduce asli () cara, invoke () cara PersonInvocationHandler () diarani:

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

   System.out.println("Hi!");
   return null;
}
"Halo!" ditampilake ing konsol, nanging iki dudu prilaku sing dikarepake: / Apa sing diupayakake yaiku nampilake "Hai!" banjur nyebutake cara asline dhewe, kanthi tembung liya, cara nelpon

proxyArnold.introduce(arnold.getName());
kudu nampilake "Hai! Jenengku Arnold", ora mung "Hai!" Kepiye carane bisa nggayuh iki? Iku ora rumit: kita mung kudu njupuk sawetara kabebasan karo handler kita lan invoke () cara :) Pay manungsa waé kanggo apa bantahan liwat cara iki:

public Object invoke(Object proxy, Method method, Object[] args)
Metode invoke () nduweni akses menyang metode asline, lan kabeh argumen (metode metode, Obyek [] args). Ing tembung liyane,, yen kita nelpon proxyArnold.introduce (arnold.getName ()) cara supaya invoke () cara disebut tinimbang introduce () cara, banjur nang cara iki kita duwe akses menyang asli introduce () cara . lan argumentasine! Akibaté, kita bisa nindakake iki:

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);
   }
}
Saiki ing cara invoke () kita wis nambahake telpon menyang metode asli. Yen saiki kita nyoba mbukak kode saka conto sadurunge:

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());
   }
}
banjur kita bakal weruh yen saiki kabeh bisa digunakake :) Output konsol:

Hi! My name is Arnold
Nalika sampeyan butuh iki? Bener, cukup asring. Pola desain "proxy dinamis" aktif digunakake ing teknologi populer ... Oh, kanthi cara, aku kelalen nyatakake yen Dynamic Proxy minangka pola desain! Sugeng, sampeyan sinau siji maneh! :) Proksi dinamis - 3Contone, aktif digunakake ing teknologi populer lan frameworks related kanggo keamanan. Bayangake sampeyan duwe 20 cara sing mung kudu ditindakake dening pangguna sing mlebu menyang program sampeyan. Nggunakake teknik sing wis sampeyan sinau, sampeyan bisa kanthi gampang nambahake 20 metode iki kanggo mriksa manawa pangguna wis ngetik kredensial sing bener tanpa duplikat kode verifikasi ing saben metode. Utawa umpamane sampeyan pengin nggawe log ing ngendi kabeh tumindak pangguna bakal direkam. Iki uga gampang ditindakake kanthi nggunakake proxy. Malah saiki, sampeyan mung bisa nambah kode kanggo conto ing ndhuwur supaya jeneng cara ditampilake nalika sampeyan nelpon invoke () , lan sing bakal gawé log super prasaja saka program kita :) Ing kesimpulan, mbayar manungsa waé kanggo siji watesan penting. Objek proxy bisa digunakake karo antarmuka, dudu kelas. Proxy digawe kanggo antarmuka. Deleng kode iki:

// Create a proxy for our arnold object
Person proxyArnold = (Person) Proxy.newProxyInstance(arnoldClassLoader, interfaces, new PersonInvocationHandler(arnold));
Ing kene kita nggawe proxy khusus kanggo antarmuka Person . Yen kita nyoba kanggo nggawe proxy kanggo kelas, IE ngganti jinis referensi lan nyoba kanggo matak kanggo kelas Man , iku ora bisa.

Person proxyArnold = (Person) Proxy.newProxyInstance(arnoldClassLoader, interfaces, new PersonInvocationHandler(arnold));

proxyArnold.introduce(arnold.getName());
Pangecualian ing thread "utama" java.lang.ClassCastException: com.sun.proxy.$Proxy0 ora bisa dikirim menyang Man Duwe antarmuka minangka syarat mutlak. Proxy bisa digunakake karo antarmuka. Iku kabeh kanggo dina iki :) Inggih, saiki iku bakal apik kanggo ngrampungake sawetara tugas! :) Nganti wektu sabanjure!
Komentar
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION