Proxy dynamique Java: qu'est-ce que c'est et comment l'utiliser?

Bonjour Ă  tous!

Eh bien, avant la nouvelle année et le début du dixième volet, le «développeur Java» plaisante complètement. Nous avons donc une leçon ouverte que nous préparons pour la publication et l'article d'aujourd'hui, à partir duquel vous en apprendrez plus sur le proxy Java dynamique: de quoi il s'agit, quand et comment l'utiliser dans du code.

Qu'est-ce qu'un proxy?

Un proxy est un modèle de conception. Nous le créons et l'utilisons pour ajouter et modifier la fonctionnalité des classes existantes. Dans ce cas, l'objet proxy est utilisé à la place de l'original. Habituellement, il utilise la même méthode que celle d'origine, et dans les classes proxy Java, étendez celles d'origine. Un proxy peut appeler une méthode sur l'objet source car il a un descripteur d'origine.

Ainsi, les classes proxy implémentent commodément de nombreuses choses:

  • enregistrer le dĂ©but et la fin de la mĂ©thode;
  • vĂ©rification supplĂ©mentaire des arguments;
  • imitation du comportement de la classe source;
  • mise en Ĺ“uvre d'une initialisation diffĂ©rĂ©e de ressources coĂ»teuses;



Tout cela se produit sans changer le code de classe d'origine. La liste complète n'est pas limitée aux exemples ci-dessus, ils n'en sont qu'une petite partie.

En pratique, la classe proxy n'implémente pas directement la fonctionnalité. Suivant le principe de la responsabilité exclusive, la classe proxy n'effectue directement que le proxy et les changements de comportement sont implémentés dans les gestionnaires. Lors de l'appel d'un objet proxy au lieu de celui d'origine, le proxy décide d'appeler la méthode d'origine ou certains gestionnaires. Le gestionnaire peut effectuer à la fois sa propre tâche et se référer à la méthode d'origine.

Bien que le modèle de proxy ne soit pas uniquement utilisé pour créer un objet proxy et une classe dans le runtime, en Java, c'est une rubrique particulièrement intéressante. Dans cet article, je me concentre sur ces procurations.

Il s'agit d'un sujet complexe qui nécessite l'utilisation de la classe de réflexion, ou la manipulation de bytecode, ou la compilation de code Java généré dynamiquement. Ou peut-être tout d'un coup. Pour empêcher la nouvelle classe d'être disponible en tant que bytecode au moment de l'exécution, le bytecode généré et le chargeur de classe seront nécessaires pour charger le bytecode. Pour créer un bytecode, utilisez cglib , bytebuddy ou le compilateur Java intégré.

L'importance de la séparation des responsabilités, dans notre cas, devient claire, il suffit de penser aux classes proxy et aux gestionnaires qu'elles appellent. Une classe proxy est générée lors de l'exécution, mais les gestionnaires qu'elle appelle peuvent être ajoutés au code source normal et compilés avec le reste du programme.

Comment l'utiliser dans notre code?

Le plus simple est d'utiliser java.lang.reflect.Proxy , qui fait partie du JDK. Cette classe peut créer directement une classe proxy ou son instance. L'utilisation d'un proxy intégré à Java est très simple. Il vous suffit d'implémenter java.lang.InvocationHandler pour que l'objet proxy puisse l'appeler. L'interface InvocationHandler est extrêmement simple et ne contient qu'une seule méthode: invoke() . Lorsqu'ils sont appelés, les arguments contiennent l'objet d'origine mandaté, la méthode appelée (en tant que reflet de l'objet Method ) et un tableau d'objets des arguments d'origine. L'extrait de code ci-dessous illustre l'application:

 package proxy; import java.lang.reflect.InvocationHandler; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.Proxy; public class JdkProxyDemo { interface If { void originalMethod(String s); } static class Original implements If { public void originalMethod(String s) { System.out.println(s); } } static class Handler implements InvocationHandler { private final If original; public Handler(If original) { this.original = original; } public Object invoke(Object proxy, Method method, Object[] args) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException { System.out.println("BEFORE"); method.invoke(original, args); System.out.println("AFTER"); return null; } } public static void main(String[] args){ Original original = new Original(); Handler handler = new Handler(original); If f = (If) Proxy.newProxyInstance(If.class.getClassLoader(), new Class[] { If.class }, handler); f.originalMethod("Hallo"); } } 

Pour appeler la méthode d'origine de l'objet source, le gestionnaire doit y accéder. Ce qui n'est pas fourni par l'implémentation du proxy Java. Vous devrez passer l'argument vous-même à l'instance de gestionnaire dans le code. (Faites attention à l'objet (généralement appelé proxy), qui est passé en argument au gestionnaire appelé. Il s'agit d'un objet proxy que Java génère dynamiquement, et non de l'objet que nous voulons proxy.) Ainsi, vous pouvez utiliser séparément des objets de gestionnaire pour chaque classe source, ainsi qu'un objet général qui sait comment appeler l'objet d'origine, s'il existe une méthode pour cela.

Dans le cas particulier, vous pouvez créer un gestionnaire d'appels et une interface proxy sans l'objet d'origine. De plus, une classe pour implémenter une interface dans le code source n'est pas requise. Il est implémenté par une classe proxy créée dynamiquement.

Si la classe mandatée n'implémente pas l'interface, vous devez envisager d'utiliser une autre implémentation proxy.

LA FIN

En attente de vos commentaires et questions. Comme toujours, soit ici, soit vous pouvez vous rendre à Vitaly pour une journée portes ouvertes .

Source: https://habr.com/ru/post/fr434214/


All Articles