Le proxy dynamique est divisé en deux méthodes : le proxy dynamique JDK et le proxy dynamique cglib.
Le proxy dynamique jdk est implémenté par le mécanisme de réflexion interne de Java, tandis que la couche inférieure du proxy dynamique cglib est implémentée à l'aide d'asm.
En général, le mécanisme de réflexion est plus efficace dans le processus de génération des classes, tandis qu'asm est plus efficace dans le processus d'exécution associé après la génération de la classe (vous pouvez mettre en cache les classes générées par asm pour résoudre le problème de problèmes d'inefficacité des processus de génération asm).
Il y a un autre point à noter : La condition préalable à l'application du proxy dynamique jdk doit être que la classe cible doit être basée sur une interface unifiée. Sans les conditions préalables ci-dessus, le proxy dynamique jdk ne peut pas être appliqué.
Il ressort de cela que le proxy dynamique jdk présente certaines limites. Le proxy dynamique implémenté par des bibliothèques de classes tierces telles que cglib est plus largement utilisé et présente plus d'avantages en termes d'efficacité.
Le code suivant utilise le mode proxy pour implémenter une fonction de conversion des caractères majuscules et minuscules.
Définition de l'interface et de la classe d'implémentation :
Interface ISomeService :
package com.ietree.basicskill.designpattern.dynamicproxy.jdk;/** * 接口类 * * @author Root */public interface ISomeService { String doFirst(); void doSecond(); }
Classe d'implémentation SomeServiceImpl :
package com.ietree.basicskill.designpattern.dynamicproxy.jdk;/** * 实现类 * * @author Root */public class SomeServiceImpl implements ISomeService { @Overridepublic String doFirst() { System.out.println("执行doFirst()..."); String result = "abcde";return result; } @Overridepublic void doSecond() { System.out.println("执行doSecond()..."); } }
Classe de proxy dynamique JDK :
package com.ietree.basicskill.designpattern.dynamicproxy.jdk;import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;import java.lang.reflect.Proxy;public class Main {public static void main(String[] args) {final ISomeService target = new SomeServiceImpl(); // 使用JDK的Proxy动态代理,要求目标类和代理类必须实现相同的接口,因为其底层的执行原理与静态代理的相同ISomeService service = (ISomeService) Proxy.newProxyInstance(// 目标类的类加载器 target.getClass().getClassLoader(),// 目标类所实现的所有接口 target.getClass().getInterfaces(), new InvocationHandler() {// proxy:代理对象// method:目标方法// args:目标方法的参数列表 @Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {// 调用目标方法Object result = method.invoke(target, args);if (result != null) { result = ((String) result).toUpperCase(); }return result; } }); String result = service.doFirst(); System.out.println(result); service.doSecond(); } }
Cglib est un excellent framework de proxy dynamique, et sa couche inférieure utilise ASM Générez dynamiquement des sous-classes de la classe proxy en mémoire et utilisez CGLIB pour implémenter des fonctions proxy dynamiques même si la classe proxy n'implémente aucune interface. CGLIB est simple et facile à utiliser, et il s'exécute beaucoup plus rapidement que le proxy dynamique Proxy du JDK :
Classe principale de CGLIB :
net.sf.cglib.proxy.Enhancer – la classe d'amélioration principale
net .sf.cglib.proxy.MethodInterceptor – la classe principale d'interception de méthode, qui est une sous-interface de l'interface de rappel et nécessite que les utilisateurs l'implémentent
net.sf.cglib.proxy.MethodProxy – java.lang.reflect du JDK . La classe proxy de la classe Method peut facilement appeler la méthode de l'objet source, par exemple en utilisant :
Object o = methodProxy.invokeSuper(proxy, args);//Bien que le premier paramètre soit l'objet proxy, il ne sera pas An. un problème de boucle infinie se produit.
L'interface net.sf.cglib.proxy.MethodInterceptor est le type de rappel le plus courant, qui est souvent utilisé par AOP basé sur un proxy pour implémenter les appels de méthode d'interception. Cette interface ne définit qu'une seule méthode
interception d'objet public (objet Object, méthode java.lang.reflect.Method, Object[] args, proxy MethodProxy) lance Throwable;
Le premier paramètre est la paire de proxy Like , les deuxième et troisième paramètres sont respectivement la méthode interceptée et les paramètres de la méthode. La méthode d'origine peut être appelée par réflexion normale à l'aide d'un objet java.lang.reflect.Method ou à l'aide d'un objet net.sf.cglib.proxy.MethodProxy. net.sf.cglib.proxy.MethodProxy est généralement préféré car il est plus rapide.
Le programme suivant implémente la fonction de conversion de cas :
Classe d'implémentation SomeService :
package com.ietree.basicskill.designpattern.dynamicproxy.cglib;/** * 实现类 * * @author Root */public class SomeService {public String doFirst() { System.out.println("执行doFirst()..."); String result = "abcde";return result; }public void doSecond() { System.out.println("执行doSecond()..."); } }
Classe proxy MyCglibFactory :
package com.ietree.basicskill.designpattern.dynamicproxy.cglib;import java.lang.reflect.Method;import net.sf.cglib.proxy.Enhancer;import net.sf.cglib.proxy.MethodInterceptor;import net.sf.cglib.proxy.MethodProxy;public class MyCglibFactory implements MethodInterceptor {private SomeService target; public MyCglibFactory() {super(); target = new SomeService(); }public SomeService myCglibCreator() {// 创建增强器对象Enhancer enhancer = new Enhancer();// 指定目标类,即父类enhancer.setSuperclass(SomeService.class);// 设置回调接口对象enhancer.setCallback(this);return (SomeService) enhancer.create(); } @Overridepublic Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {// 调用目标方法Object result = method.invoke(target, args);if (result != null) { result = ((String) result).toUpperCase(); }return result; } }
Test :
package com.ietree.basicskill.designpattern.dynamicproxy.cglib;public class Main {public static void main(String[] args) { SomeService service = new MyCglibFactory().myCglibCreator(); String result = service.doFirst(); System.out.println("result = " + result); service.doSecond(); } }
Résultat de l'exécution :
执行doFirst()... result = ABCDE 执行doSecond()...
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!