Dua kaedah tersebut ialah: 1. Proksi dinamik JDK, menggunakan mekanisme pantulan untuk menjana kelas tanpa nama yang melaksanakan antara muka proksi, dan memanggil InvokeHandler sebelum memanggil kaedah tertentu 2. proksi dinamik CGLIB, menggunakan asm pakej sumber terbuka, Muatkan fail kelas kelas objek proksi dan proseskannya dengan mengubah suai kod baitnya untuk menjana subkelas.
Persekitaran pengendalian tutorial ini: sistem Windows 7, versi Java 8, komputer DELL G3.
Proksi dinamik ialah senario refleksi aplikasi yang sangat penting. Proksi dinamik sering digunakan dalam beberapa rangka kerja Java. Contohnya, antara muka AOP Spring dan SPI Dubbo dilaksanakan berdasarkan proksi dinamik Java.
Terdapat dua cara untuk proksi secara dinamik:
Proksi dinamik JDK: Gunakan mekanisme refleksi untuk menjana proksi pelaksanaan antara muka Untuk kelas tanpa nama, hubungi InvokeHandler sebelum memanggil kaedah tertentu.
Proksi dinamik CGLIB: Gunakan pakej sumber terbuka ASM (sumber terbuka kod bait Java, kod bait operasi) untuk memuatkan fail kelas kelas objek proksi dan mengubah suai kod bahagian aksaranya menjana subkelas untuk dikendalikan.
Perbezaan: Ejen JDK hanya boleh menjana agen untuk kelas yang melaksanakan antara muka; CGlib melaksanakan ejen untuk kelas, menjana subkelas untuk kelas yang ditentukan dan mengatasinya. kaedah, yang dilaksanakan melalui kelas yang diwarisi, tidak boleh memproksi kelas yang diubah suai akhir.
Paksa penggunaan CGlib
<!-- proxy-target-class="false"默认使用JDK动态代理 --> <aop:aspectj-autoproxy proxy-target-class="true"/> <aop-config proxy-target-class="true"> <!-- 切面详细配置 --> </aop-config>
Contoh kod khusus:
/** * 目标接口类 */ public interface UserManager { public void addUser(String id, String password); public void delUser(String id); }
/** * 接口实现类 */ public class UserManagerImpl implements UserManager { @Override public void addUser(String id, String password) { System.out.println("调用了UserManagerImpl.addUser()方法!"); } @Override public void delUser(String id) { System.out.println("调用了UserManagerImpl.delUser()方法!"); } }
/** * JDK动态代理类 */ public class JDKProxy implements InvocationHandler { // 需要代理的目标对象 private Object targetObject; public Object newProxy(Object targetObject) { // 将目标对象传入进行代理 this.targetObject = targetObject; // 返回代理对象 return Proxy.newProxyInstance(targetObject.getClass().getClassLoader(), targetObject.getClass().getInterfaces(), this); } // invoke方法 @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { // 进行逻辑处理的函数 checkPopedom(); Object ret = null; // 调用invoke方法 ret = method.invoke(targetObject, args); return ret; } private void checkPopedom() { // 模拟检查权限 System.out.println("检查权限:checkPopedom()!"); } }
/** * CGlib动态代理类 */ public class CGLibProxy implements MethodInterceptor { // CGlib需要代理的目标对象 private Object targetObject; public Object createProxyObject(Object obj) { this.targetObject = obj; Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(obj.getClass()); enhancer.setCallback(this); Object proxyObj = enhancer.create(); return proxyObj; } @Override public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { Object obj = null; // 过滤方法 if ("addUser".equals(method.getName())) { // 检查权限 checkPopedom(); } obj = method.invoke(targetObject, args); return obj; } private void checkPopedom() { System.out.println("检查权限:checkPopedom()!"); } }
/** * 测试类 */ public class ProxyTest { public static void main(String[] args) { UserManager userManager = (UserManager)new CGLibProxy().createProxyObject(new UserManagerImpl()); System.out.println("CGLibProxy:"); userManager.addUser("tom", "root"); System.out.println("JDKProxy:"); JDKProxy jdkProxy = new JDKProxy(); UserManager userManagerJDK = (UserManager)jdkProxy.newProxy(new UserManagerImpl()); userManagerJDK.addUser("tom", "root"); } }
// 运行结果 CGLibProxy: 检查权限checkPopedom()! 调用了UserManagerImpl.addUser()方法! JDKProxy: 检查权限checkPopedom()! 掉用了UserManagerImpl.addUser()方法!
Ringkasan :
1. Ejen JDK menggunakan mekanisme pantulan untuk melaksanakan ejen dinamik aop Ejen CGLIB menggunakan rangka kerja pemprosesan kod bait untuk menjana subkelas dengan mengubah kod bait. Oleh itu, kaedah proksi dinamik jdk lebih cekap dalam mencipta objek proksi dan mempunyai kecekapan pelaksanaan yang lebih rendah mempunyai kecekapan penciptaan yang lebih rendah dan kecekapan pelaksanaan yang lebih tinggi daripada kelas antara muka , amanahkan pengendali untuk memanggil kaedah kelas pelaksanaan asal dalam kelas pelaksanaan yang dihasilkan secara dinamik CGLIB menggunakan mekanisme warisan Secara khusus, kelas proksi dan kelas proksi adalah perhubungan warisan, jadi kelas proksi boleh diberikan kepada kelas proksi. . Jika kelas proksi mempunyai antara muka, jadi kelas proksi juga boleh diberikan kepada antara muka.
(Tutorial disyorkan:
Tutorial pengenalan JavaAtas ialah kandungan terperinci Apakah dua cara proksi dinamik?. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!