Proksi dinamis JAVA
mode proksi
Pola agen adalah pola desain Java yang umum digunakan. Karakteristiknya adalah bahwa kelas agen dan kelas delegasi memiliki antarmuka yang sama. Kelas agen terutama bertanggung jawab untuk memproses pesan untuk kelas delegasi, memfilter pesan, meneruskan pesan ke kelas delegasi , dan memproses pesan setelahnya. Biasanya ada hubungan antara kelas proxy dan kelas delegasi. Objek kelas proxy dikaitkan dengan objek kelas delegasi. Objek kelas proxy itu sendiri tidak benar-benar mengimplementasikan layanan, tetapi dengan memanggil metode yang relevan dari objek kelas delegasi. Menyediakan layanan khusus.
Menurut periode pembuatan agen, kelas agen dapat dibagi menjadi dua jenis.
Proksi statis: Dibuat oleh pemrogram atau dibuat secara otomatis oleh alat tertentu dan kemudian dikompilasi. Sebelum program dijalankan, file .class dari kelas proxy sudah ada.
Proksi dinamis: Dibuat secara dinamis menggunakan mekanisme refleksi saat program sedang berjalan.
Pertama lihat proxy statis:
1.Hitung.java
Copy kode kodenya sebagai berikut:
paket net.battier.dao;
/**
* Tentukan antarmuka akun
*
* @penulis Administrator
*
*/
antarmuka publik Jumlah {
// Lihat metode akun
public void queryCount();
//Ubah metode akun
kekosongan publik updateCount();
}
2. HitungImpl.java
Copy kode kodenya sebagai berikut:
paket net.battier.dao.impl;
impor net.battier.dao.Count;
/**
* Kelas delegasi (termasuk logika bisnis)
*
* @penulis Administrator
*
*/
kelas publik CountImpl mengimplementasikan Count {
@Mengesampingkan
kekosongan publik queryCount() {
System.out.println("Lihat metode akun...");
}
@Mengesampingkan
kekosongan publik updateCount() {
System.out.println("Ubah metode akun...");
}
}
CountProxy.java
paket net.battier.dao.impl;
impor net.battier.dao.Count;
/**
* Ini adalah kelas proxy (kelas implementasi CountImpl yang ditingkatkan)
*
* @penulis Administrator
*
*/
kelas publik CountProxy mengimplementasikan Count {
hitungan Impl pribadi hitungan Impl;
/**
* Ganti konstruktor default
*
* @param countImpl
*/
CountProxy publik(CountImpl countImpl) {
this.countImpl = countImpl;
}
@Mengesampingkan
kekosongan publik queryCount() {
System.out.println("Sebelum transaksi diproses");
// Panggil metode kelas delegasi;
countImpl.queryCount();
System.out.println("Setelah transaksi diproses");
}
@Mengesampingkan
kekosongan publik updateCount() {
System.out.println("Sebelum transaksi diproses");
// Panggil metode kelas delegasi;
countImpl.updateCount();
System.out.println("Setelah transaksi diproses");
}
}
3. TestCount.java
Copy kode kodenya sebagai berikut:
paket net.battier.test;
impor net.battier.dao.impl.CountImpl;
impor net.battier.dao.impl.CountProxy;
/**
*Tes Kelas Hitungan
*
* @penulis Administrator
*
*/
Kelas publik TestCount {
public static void main(String[] args) {
CountImpl countImpl = CountImpl baru();
CountProxy countProxy = CountProxy baru(countImpl);
countProxy.updateCount();
countProxy.queryCount();
}
}
Mengamati kodenya, Anda dapat menemukan bahwa setiap kelas proxy hanya dapat melayani satu antarmuka. Dengan cara ini, terlalu banyak proxy yang pasti akan dihasilkan selama pengembangan program. Selain itu, semua operasi proxy adalah sama kecuali metode yang mereka panggil harus diulang saat ini. Cara terbaik untuk mengatasi masalah ini adalah dengan menggunakan kelas proxy untuk menyelesaikan semua fungsi proxy. Dalam hal ini, proxy dinamis harus digunakan untuk menyelesaikannya.
Mari kita lihat proxy dinamis:
Proksi dinamis JDK berisi kelas dan antarmuka:
Antarmuka InvocationHandler:
antarmuka publik InvocationHandler {
pemanggilan Objek publik (Proksi objek, Metode metode, Objek [] args) melempar Throwable;
}
Deskripsi parameter:
Proksi objek: mengacu pada objek yang diproksi.
Metode metode: metode yang akan dipanggil
Object[] args: parameter yang diperlukan saat memanggil metode
Anda dapat menganggap subkelas antarmuka InvocationHandler sebagai kelas operasi akhir dari proksi, menggantikan ProxySubject.
Kelas proksi:
Kelas Proxy adalah kelas yang berspesialisasi dalam operasi proxy. Kelas ini dapat digunakan untuk menghasilkan kelas implementasi secara dinamis untuk satu atau lebih antarmuka.
Objek statis publik newProxyInstance(pemuat ClassLoader, antarmuka Kelas<?>[],
Pengendali Permintaan h)
melempar IllegalArgumentException
Deskripsi parameter:
Pemuat ClassLoader: pemuat kelas
Antarmuka kelas<?>[]: dapatkan semua antarmuka
InvocationHandler h: Dapatkan instance subkelas dari antarmuka InvocationHandler
Ps: pemuat kelas
Sebuah instance dari kelas ClassLoader diperlukan dalam metode newProxyInstance() di kelas Proxy. ClassLoader sebenarnya berhubungan dengan pemuat kelas. Ada tiga pemuat kelas utama di Java;
Booststrap ClassLoader: Loader ini ditulis dalam C++ dan tidak dapat dilihat dalam pengembangan umum;
Extension ClassLoader: digunakan untuk memuat kelas ekstensi, umumnya sesuai dengan kelas di direktori jre/lib/ext;
AppClassLoader: (default) memuat kelas yang ditentukan oleh classpath, yang merupakan pemuat yang paling umum digunakan.
proksi dinamis
Berbeda dengan kelas proxy statis, terdapat kelas proxy dinamis. Bytecode kelas proxy dinamis dihasilkan secara dinamis oleh mekanisme refleksi Java saat program sedang berjalan, tanpa perlu pemrogram menulis kode sumbernya secara manual. Kelas proxy dinamis tidak hanya menyederhanakan pekerjaan pemrograman, tetapi juga meningkatkan skalabilitas sistem perangkat lunak, karena mekanisme refleksi Java dapat menghasilkan semua jenis kelas proxy dinamis. Kelas Proxy dan antarmuka InvocationHandler dalam paket java.lang.reflect menyediakan kemampuan untuk menghasilkan kelas proxy dinamis.
Contoh proksi dinamis:
1.BookFacade.java
Copy kode kodenya sebagai berikut:
paket net.battier.dao;
antarmuka publik BookFacade {
public void addBook();
}
2.BookFacadeImpl.java
Copy kode kodenya sebagai berikut:
paket net.battier.dao.impl;
impor net.battier.dao.BookFacade;
kelas publik BookFacadeImpl mengimplementasikan BookFacade {
@Mengesampingkan
kekosongan publik addBook() {
System.out.println("Tambahkan metode buku...");
}
}
BookFacadeProxy.java
paket net.battier.proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* Kelas proxy proksi dinamis JDK
*
* @siswa penulis
*
*/
kelas publik BookFacadeProxy mengimplementasikan InvocationHandler {
sasaran Objek pribadi;
/**
* Ikat objek delegasi dan kembalikan kelas proxy
* @param sasaran
* @kembali
*/
pengikatan Objek publik(Target objek) {
this.target = sasaran;
//Dapatkan objek proksi
kembalikan Proxy.newProxyInstance(target.getClass().getClassLoader(),
target.getClass().getInterfaces(), this); //Untuk mengikat antarmuka (ini adalah kelemahan, cglib menebus kekurangan ini)
}
@Mengesampingkan
/**
* Metode panggilan
*/
pemanggilan Objek publik (Proksi objek, Metode metode, Objek[] args)
lemparan Dapat dilempar {
Hasil objek=null;
System.out.println("Segalanya dimulai");
//metode eksekusi
hasil=metode.invoke(target, args);
System.out.println("Akhir dari segalanya");
hasil pengembalian;
}
}
3. UjiProxy.java
Copy kode kodenya sebagai berikut:
paket net.battier.test;
impor net.battier.dao.BookFacade;
impor net.battier.dao.impl.BookFacadeImpl;
impor net.battier.proxy.BookFacadeProxy;
Proksi Tes kelas publik {
public static void main(String[] args) {
Proksi BookFacadeProxy = BookFacadeProxy baru();
BookFacade bookProxy = (BookFacade) proxy.bind(New BookFacadeImpl());
bookProxy.addBook();
}
}
Namun, proksi dinamis JDK bergantung pada implementasi antarmuka. Jika beberapa kelas tidak mengimplementasikan antarmuka, proksi JDK tidak dapat digunakan, sehingga proksi dinamis cglib harus digunakan.
Proksi dinamis Cglib
Mekanisme proksi dinamis JDK hanya dapat memproksi kelas yang mengimplementasikan antarmuka. Kelas yang tidak dapat mengimplementasikan antarmuka tidak dapat mengimplementasikan proksi dinamis JDK. cglib mengimplementasikan proksi untuk kelas. Prinsipnya adalah menghasilkan subkelas untuk kelas target yang ditentukan, dan mengganti metode untuk mencapai peningkatan , tetapi karena warisan digunakan, kelas yang terakhir dimodifikasi tidak dapat diproksi.
Contoh
1.BookFacadeCglib.java
Copy kode kodenya sebagai berikut:
paket net.battier.dao;
antarmuka publik BookFacade {
public void addBook();
}
2.BookCadeImpl1.java
Copy kode kodenya sebagai berikut:
paket net.battier.dao.impl;
/**
* Ini adalah kelas implementasi yang tidak mengimplementasikan antarmuka
*
* @siswa penulis
*
*/
kelas publik BookFacadeImpl1 {
kekosongan publik addBook() {
System.out.println("Metode umum untuk menambahkan buku...");
}
}
3.BookFacadeProxy.java
Copy kode kodenya sebagai berikut:
paket net.battier.proxy;
import java.lang.reflect.Method;
import net.sf.cglib.proxy.Enhancer;
impor net.sf.cglib.proxy.MethodInterceptor;
impor net.sf.cglib.proxy.MethodProxy;
/**
* Gunakan proksi dinamis cglib
*
* @siswa penulis
*
*/
kelas publik BookFacadeCglib mengimplementasikan MethodInterceptor {
sasaran Objek pribadi;
/**
* Buat objek proxy
*
* @param sasaran
* @kembali
*/
Objek publik getInstance(Target objek) {
this.target = sasaran;
Penambah penambah = Peningkat baru();
penambah.setSuperclass(ini.target.getClass());
// metode panggilan balik
penambah.setCallback(ini);
//Buat objek proksi
kembalikan penambah.create();
}
@Mengesampingkan
// metode panggilan balik
intersepsi Objek publik(Obj objek, Metode metode, Objek[] args,
Proksi MethodProxy) melempar Throwable {
System.out.println("Segalanya dimulai");
proxy.invokeSuper(obj, args);
System.out.println("Akhir dari semuanya");
kembalikan nol;
}
}
4. TesCglib.java
Copy kode kodenya sebagai berikut:
paket net.battier.test;
impor net.battier.dao.impl.BookFacadeImpl1;
impor net.battier.proxy.BookFacadeCglib;
kelas publik TestCglib {
public static void main(String[] args) {
BookFacadeCglib cglib=BookFacadeCglib baru();
BookFacadeImpl1 bookCglib=(BookFacadeImpl1)cglib.getInstance(BookFacadeImpl1());
bookCglib.addBook();
}
}