Maison  >  Article  >  Java  >  qu'est-ce que le proxy Java

qu'est-ce que le proxy Java

angryTom
angryTomoriginal
2019-11-13 11:37:374625parcourir

qu'est-ce que le proxy Java

Qu'est-ce qu'un proxy Java

Qu'est-ce qu'un proxy En fait, c'est facile à comprendre ? Il n'accède pas directement à la cible, mais est accessible via une couche intermédiaire, comme ceci :

quest-ce que le proxy Java

Proxy statique de Java

Par exemple, si certains de nos fruits, comme les bananes, les pommes, etc., écrits en code Java, ressemblent probablement à ceci :

(Tutoriel recommandé : tutoriel Java )

//Fruit.java/**
 * 水果的接口
 */public interface Fruit {    /**
     * 获取水果的名字
     */
    public String getName();
}//Apple.javapublic class Apple implements Fruit {    @Override
    public String getName() {        return "苹果";
    }
}//Banana.javapublic class Banana implements Fruit {    @Override
    public String getName() {        return "香蕉";
    }
}

Pour manger un fruit, il faut l'éplucher. Vous ne pouvez pas écrire une sous-classe pour chaque fruit. Par conséquent, nous pouvons fabriquer un agent et peler la pomme avant de la manger. Tout comme ce qui suit, enveloppez le fruit original dans une couche :


//PeelFruitProxy.java/**
 * 代理,让每个水果去皮
 */public class PeelFruitProxy implements Fruit {    private Fruit mFruit;    public PeelFruit(Fruit fruit) {        this.mFruit = fruit;
    }    @Override
    public String getName() {
        System.out.println("proxt:" + proxy.getClass().getName());        return "去皮的" + mFruit.getName();
    }
}

Ajoutez une classe de test, la classe de test est la suivante :

//Main.javapublic class Main {    public static void main(String[] args) {
        Apple apple=new Apple();//原始的苹果
        Banana banana=new Banana();//原始的香蕉

        PeelFruitProxy peelApple=new PeelFruitProxy(apple);//代理,添加去皮功能
        PeelFruitProxy peelBanana=new PeelFruitProxy(banana);//代理,添加去皮功能
        System.out.println(peelApple.getName());
        System.out.println(peelBanana.getName());
    }
}

Ce qui précède est le proxy statique de Java Pour faire simple, il s'agit d'envelopper l'objet cible d'origine avec un calque, d'ajouter de nouveaux éléments, puis d'appeler la cible elle-même. Mais s’il s’agit simplement d’un proxy statique, une interface nécessite un proxy, et est-ce très lourd à mettre en œuvre ?

Le proxy dynamique de Java

En Java, il existe une classe appelée Proxy qui fait cela, et vous pouvez directement utiliser la réflexion et l'interception du proxy. Commençons par présenter brièvement cette classe. En fait, la méthode statique la plus couramment utilisée est Proxt.newProxyInstance(), qui ressemble à ceci :

public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)

Tout d'abord, nous devons implémenter InvocationHandler, implémenter la méthode d'invocation et appeler. l'objet cible, la méthode d'invocation sera appelée en premier et l'implémenteur doit appeler activement la méthode appelée dans cette méthode.

//FruitInvocationHandler.java/**
 * 调用方法拦截器
 */public class FruitInvocationHandler implements InvocationHandler {    private Fruit mFruit;    public FruitInvocationHandler(Fruit fruit) {        this.mFruit = fruit;
    }    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        String result = (String) method.invoke(mFruit, args);//需要在这个方法里面,主动调用被代理的对象。
        return "去皮的" + result;
    }
}

Exécutez-le :

//Main.Javapublic class Main {    public static void main(String[] args) {
        Apple apple = new Apple();
        Fruit proxyApple = (Fruit) Proxy.newProxyInstance(Fruit.class.getClassLoader(), new Class[]{Fruit.class}, new FruitInvocationHandler(apple));
        System.out.println(proxyApple.getClass().getName());
        System.out.println(proxyApple.getName());

        Banana banana = new Banana();
        Fruit proxyBanana = (Fruit) Proxy.newProxyInstance(Fruit.class.getClassLoader(), new Class[]{Fruit.class}, new FruitInvocationHandler(banana));
        System.out.println(proxyApple.getClass().getName());
        System.out.println(proxyBanana.getName());
    }
}

quest-ce que le proxy Java

Cette méthode consiste à générer un PeelFruitProxy comme mentionné ci-dessus (bien sûr, le nom que nous voyons est : com.sun . proxy.$Proxy0), il est généré dynamiquement pour éviter d'avoir à l'écrire à chaque fois. C'est aussi la raison pour laquelle on l'appelle un proxy dynamique, car nous pouvons proxy n'importe quelle classe au moment de l'exécution. AOP dans de nombreux programmes est implémenté de cette manière, mais nous avons trouvé certaines caractéristiques. Le deuxième paramètre de newProxyInstance() est une liste d'interfaces. Pourquoi y a-t-il cette liste ?

Parce que notre classe proxy générée dynamiquement doit également implémenter une interface, afin qu'elle puisse être facilement transformée vers le bas et utiliser ses méthodes. Sinon, la classe générée aura un nom de classe comme com.sun.proxy.$. Proxy0 et est en mémoire, la méthode générée ne peut pas être appelée. ** Par conséquent, cette méthode de proxy dynamique présente un inconvénient fatal, c'est-à-dire que la classe proxy doit implémenter l'interface. **

Procureur CGLib

cglib is a powerful, high performance and quality Code Generation Library, It is used to extend JAVA classes and implements interfaces at runtime.

Une autre implémentation de proxy Java bien connue est CGLib (Code Generation Library), un framework de génération de code basé sur ASM, vous pouvez l'utiliser Pour générer dynamiquement des classes puis implémenter l'interception des méthodes, vous pouvez éviter le problème du proxy dynamique du JDK, qui nécessite que la classe cible implémente l'interface. En d’autres termes, CGLib peut être utilisé pour générer le PeelFruitProxy mentionné ci-dessus.

Laissez-moi vous présenter brièvement comment l'utiliser. Tout d'abord, cette CGLib est une bibliothèque tierce dont nous devons dépendre :

compilez 'cglib:cglib:3.2.8. '


La dernière version peut être vue ici (nouvelle version) [https://github.com/cglib/cglib/releases] Alors essayons, implémentons l'agent ci-dessus

//FruitMethodInterceptor.java/**
 * CGLib代理的方法拦截器
 */public class FruitMethodInterceptor implements MethodInterceptor{    @Override
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
        String result = (String) proxy.invokeSuper(obj, args);//主要,这里调用的是父类,也就是说, 生成的类和原始类是继承关系
        return "去皮的"+result;
    }
}//Main.javapublic class Main {    public static void main(String[] args) {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(Apple.class);
        enhancer.setCallback(new FruitMethodInterceptor());
        Apple apple = (Apple) enhancer.create();
        System.out.println(apple.getClass().getName());
        System.out.println(apple.getName());
    }
}

run L'effet est le suivant :

quest-ce que le proxy Java

On voit que la même fonction est implémentée, mais Apple n'est plus la classe Apple d'origine, elle est devenue com .zjiecode.learn.java.proxy.Apple$$EnhancerByCGLIB$$44ade224, oui, nous utilisons en fait cette classe, pas l'Apple d'origine. Cette classe hérite d'Apple et implémente enfin le proxy pour la classe Apple. De cette façon, étant donné que l'héritage est utilisé, il n'est pas nécessaire que la classe mandatée implémente l'interface. Bien entendu, il peut également implémenter des agents via des interfaces.

Résumé

Le premier type de proxy n'est pas mentionné ici. Il ne convient qu'à un proxy à interface unique et est décidé au moment de la compilation.

Les deuxième et troisième types de proxys sont tous des proxys dynamiques, mais nous voyons qu'il existe des différences :

1) Le proxy dynamique du JDK ne peut implémenter que des proxys d'interface et est un objet proxy packagé (. instance de classe), c'est-à-dire que lors du processus proxy, il y a deux objets, un objet proxy et un objet cible. L'objet cible est empaqueté dans l'objet proxy.

2) Le proxy de CGLib hérite de l'objet cible, génère une nouvelle classe, puis implémente le proxy de cette façon, il y a un objet proxy dans la mémoire et aucun héritage direct n'est utilisé. La méthode

génère des classes proxy au moment de l'exécution, ce qui est différent de javapoet qui génère des classes au moment de la compilation.

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!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Article précédent:A quoi ça sert en JavaArticle suivant:A quoi ça sert en Java