Untuk memproksi kelas dengan proksi dinamis jdk, kelas yang diproksi harus mengimplementasikan setidaknya satu antarmuka, dan hanya metode di antarmuka yang dapat diproksi.
Implementasi proxy dinamis di jdk secara umum dibagi menjadi tiga langkah:
1. Tulis antarmuka dan kelas implementasi.
2. Tulis prosesor yang mengimplementasikan antarmuka InvocationHandler. Antarmuka ini hanya memiliki satu metode, dan tanda tangannya adalah pemanggilan Objek publik (Proxy objek, metode Metode, Objek[] args)
throws Throwable; Anda dapat menambahkan kode Anda sendiri dalam metode implementasi prosesor sebelum dan sesudah pemanggilan metode untuk melakukan intersepsi dinamis. Perlu dicatat bahwa kelas proxy dinamis yang dihasilkan oleh proxy bukanlah kelas sebenarnya yang kita proksi, jadi kita dapat menambahkan variabel anggota bertipe Object ke prosesor untuk menunjuk ke kelas yang benar-benar ingin kita proksi (yaitu, kelas kelas di langkah 1 kelas implementasi).
3. Gunakan metode newProxyInstance dari kelas java.lang.reflect.Proxy untuk menghasilkan kelas proksi dinamis. Untuk semua panggilan ke metode proxy, Anda dapat langsung memanggil metode kelas proxy dinamis yang dihasilkan, tetapi Anda harus terlebih dahulu melakukan konversi tipe paksa dan mengubahnya menjadi antarmuka metode yang ingin kita panggil.
Analisis prinsip JDK:
Dengan menganalisis kode sumber Proxy, Anda dapat melihat pembuatan kelas proxy dinamis secara mendetail. Metode newProxyInstance pertama-tama menghasilkan instance Kelas dari kelas proksi dinamis, lalu memanggil konstruktornya yang tipe parameternya adalah InvocationHandler untuk menghasilkan kelas proksi dinamis dan kembali.
Bagaimana cara menghasilkan instance Kelas dari kelas proksi dinamis? Kelas ProxyGenerator digunakan untuk menghasilkan aliran byte kelas dari kelas proksi dinamis dan memuatnya ke dalam area metode.
Menganalisis proses pembuatan aliran byte kelas, kita dapat melihat bahwa ia menggunakan Proxy sebagai kelas induknya untuk mengimplementasikan semua metode antarmuka yang akan diproksi. Badan implementasi setiap metode terutama memanggil metode pemanggilan prosesor.
Kode utama proses pembuatan aliran byte kelas adalah sebagai berikut:
Copy kode kodenya sebagai berikut:
byte pribadi[] menghasilkanClassFile()
{
addProxyMethod(hashCodeMethod, java/lang/Objek);
addProxyMethod(equalsMethod, java/lang/Objek);
addProxyMethod(toStringMethod, java/lang/Objek);
for(int i = 0; i < antarmuka.panjang; i++)
{
Metode amethod[] = antarmuka[i].getMethods();
for(int k = 0; k < amethod.length; k++)
addProxyMethod(amethod[k], antarmuka[i]);
}
daftar daftar;
for(Iterator iterator = proxyMethods.values().iterator(); iterator.hasNext(); checkReturnTypes(daftar))
daftar = (Daftar)iterator.next();
mencoba
{
metode.tambahkan(generateConstructor());
for(Iterator iterator1 = proxyMethods.values().iterator(); iterator1.hasNext();)
{
Daftar daftar1 = (Daftar)iterator1.next();
Iterator iterator2 = daftar1.iterator();
while(iterator2.hasNext())
{
Metode Proxy metode proxy = (Metode Proxy)iterator2.next();
field.add(new FieldInfo(proxymethod.methodFieldName, "Ljava/lang/reflect/Method;", 10));
metode.tambahkan(<SPAN style="COLOR: red">proxymethod.generateMethod()</SPAN><SPAN style="COLOR: #000000">);</SPAN>
Copy kode kodenya sebagai berikut:
}
}
metode.tambahkan(generateStaticInitializer());
}
menangkap(IOException ioException)
{
throw new InternalError("Pengecualian I/O tak terduga");
}
if(metode.ukuran() > 65535)
throw new IllegalArgumentException("batas metode terlampaui");
if(bidang.ukuran() > 65535)
throw new IllegalArgumentException("batas bidang terlampaui");
cp.getClass(dotToSlash(namakelas));
cp.getClass("java/lang/reflect/Proxy");
for(int j = 0; j < antarmuka.panjang; j++)
cp.getClass(dotToSlash(antarmuka[j].getName()));
cp.setReadOnly();
ByteArrayOutputStream bytearrayoutputstream = ByteArrayOutputStream();
DataOutputStream dataoutputstream = DataOutputStream baru(bytearrayoutputstream);
mencoba
{
dataoutputstream.writeInt(-889275714);
dataoutputstream.writeShort(0);
dataoutputstream.writeShort(49);
cp.write(dataoutputstream);
dataoutputstream.writeShort(49);
dataoutputstream.writeShort(cp.getClass(dotToSlash(namakelas)));
dataoutputstream.writeShort(cp.getClass("java/lang/reflect/Proxy"));
dataoutputstream.writeShort(antarmuka.panjang);
for(int l = 0; l < antarmuka.panjang; l++)
dataoutputstream.writeShort(cp.getClass(dotToSlash(antarmuka[l].getName())));
dataoutputstream.writeShort(fields.size());
Info lapangan Info Lapangan;
Copy kode kodenya sebagai berikut:
//Tambahkan atribut
for(Iterator iterator3 = field.iterator(); iterator3.hasNext(); fieldinfo.write(dataoutputstream))
fieldinfo = (FieldInfo)iterator3.next();
//Tambahkan metode
dataoutputstream.writeShort(metode.ukuran());
Info Metode metodeinfo;
for(Iterator iterator4 = metode.iterator(); iterator4.hasNext(); metodeinfo.write(dataoutputstream))
methodinfo = (MethodInfo)iterator4.next();
dataoutputstream.writeShort(0);
}
menangkap(IOException ioException1)
{
throw new InternalError("Pengecualian I/O tak terduga");
}
kembalikan bytearrayoutputstream.toByteArray();
}
Catatan: Bagian merah dalam kode, proxymethod.generateMethod(), menghasilkan isi metode untuk setiap metode. Dengan melihat kode sumber, kita dapat melihat bahwa semuanya memanggil metode pemanggilan prosesor implementasi antarmuka InvocationHandler.