Maison > Java > JavaBase > le corps du texte

Le principe du proxy dynamique Java

Libérer: 2019-11-29 17:06:40
avant
1965 Les gens l'ont consulté

Le principe du proxy dynamique Java

L'émergence du mécanisme de proxy dynamique Java permet aux développeurs Java d'obtenir dynamiquement des classes proxy sans écrire manuellement des classes proxy. Ils peuvent simplement spécifier un ensemble d'interfaces et déléguer des objets de classe. (Recommandé : Tutoriel vidéo Java)

La classe proxy sera responsable de la distribution de tous les appels de méthode à l'objet délégué pour l'exécution de la réflexion. Pendant le processus d'exécution de la répartition, les développeurs peuvent également ajuster si nécessaire. Déléguez les objets de classe et leurs fonctions, il s'agit d'un cadre de proxy très flexible et flexible. Ensuite, nous commençons à découvrir les agents dynamiques.

Une brève description du proxy dynamique

Dans le mécanisme de proxy dynamique de Java, il existe deux classes ou interfaces importantes, l'une est InvocationHandler( Interface), l'autre est Proxy (Classe).

1. Description d'InvocationHandler (interface) :

InvocationHandler is the interface implemented by the invocation handler of a proxy instance. 

Each proxy instance has an associated invocation handler. When a method is invoked on a proxy instance, the method invocation is encoded and dispatched to the invoke method of its invocation handler.
Copier après la connexion

Chaque classe proxy dynamique doit implémenter l'interface InvocationHandler, et chaque instance de classe proxy est associée lorsque nous atteignons un gestionnaire. , lorsque nous appelons une méthode via l'objet proxy, l'appel de cette méthode sera transmis pour être appelé par la méthode d'invocation de l'interface InvocationHandler. Jetons un coup d'œil à la seule méthode de l'interface InvocationHandler, la méthode Invoc :

Object invoke(Object proxy, Method method, Object[] args) throws Throwable
Copier après la connexion

Cette méthode reçoit trois paramètres et renvoie un type Object. Leurs significations respectives sont les suivantes :

proxy : fait référence à l'objet réel pour lequel nous représentons un proxy

method : fait référence à l'objet Method que nous voulons appeler la méthode de l'objet réel

args : fait référence aux paramètres reçus lors de l'appel d'une méthode de l'objet réel L'objet renvoyé par le paramètre

fait référence au type de retour de la méthode objet réel. Ce qui précède sera compris en profondeur dans les exemples suivants.

the value to return from the method invocation on the proxy instance.
Copier après la connexion

2. Description du proxy (classe) :

Proxy fournit des méthodes statiques pour créer des classes et des instances de proxy dynamiques, et c'est également la superclasse de toutes les classes de proxy dynamiques créées par ces méthodes.

La fonction de la classe Proxy est de créer dynamiquement un objet proxy. Nous utilisons souvent la méthode newProxyInstance :

public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces,  InvocationHandler h)  throws IllegalArgumentException
Copier après la connexion

Compréhension des paramètres :

// 一个ClassLoader对象,定义了由哪个ClassLoader对象来对生成的代理对象进行加载
loader - the class loader to define the proxy class  
// 一个Interface对象的数组,表示的是我将要给我需要代理的对象提供一组什么接口
interfaces - the list of interfaces for the proxy class to implement 
// 一个InvocationHandler对象,表示的是当我这个动态代理对象在调用方法的时候,会关联到哪一个InvocationHandler对象上
h - the invocation handler to dispatch method invocations to
Copier après la connexion

Compréhension des résultats de retour : Une instance d'un objet proxy

une instance de proxy avec le gestionnaire d'invocation spécifié d'une classe proxy définie par le chargeur de classe spécifié et qui implémente les interfaces spécifiées

Proxy Java simple

Nous créons un projet Java pour tester et comprendre le proxy dynamique, La structure du projet est comme suit :

Le principe du proxy dynamique Java

1. Définissez d'abord une interface Interface et ajoutez deux méthodes.

package com.huhx.proxy;

public interface Interface {
    void getMyName();

    String getNameById(String id);
}
Copier après la connexion

2. Définissez une classe réelle qui implémente l'interface ci-dessus, RealObject :

package com.huhx.proxy;

public class RealObject implements Interface {
    @Override
    public void getMyName() {
        System.out.println("my name is huhx");
    }

    @Override
    public String getNameById(String id) {
        System.out.println("argument id: " + id);
        return "huhx";
    }
}
Copier après la connexion

3. Définissez un objet proxy, qui est également implémenté L'interface mentionnée ci-dessus :

package com.huhx.proxy;

public class SimpleProxy implements Interface {
    private Interface proxied;

    public SimpleProxy(Interface proxied) {
        this.proxied = proxied;
    }

    @Override
    public void getMyName() {
        System.out.println("proxy getmyname");
        proxied.getMyName();
    }

    @Override
    public String getNameById(String id) {
        System.out.println("proxy getnamebyid");
        return proxied.getNameById(id);
    }
}
Copier après la connexion

4. SimpleMain teste les résultats ci-dessus dans la méthode Main :

package com.huhx.proxy;

public class SimpleMain {
    private static void consume(Interface iface) {
        iface.getMyName();
        String name = iface.getNameById("1");
        System.out.println("name: " + name);
    }

    public static void main(String[] args) {
        consume(new RealObject());
        System.out.println("========================================================");
        consume(new SimpleProxy(new RealObject()));
    }
}
Copier après la connexion

5. L'exécution les résultats sont les suivants :

my name is huhx
argument id: 1
name: huhx
========================================================
proxy getmyname
my name is huhx
proxy getnamebyid
argument id: 1
name: huhx
Copier après la connexion

Le proxy dynamique de Java

Après avoir terminé le proxy Java simple ci-dessus, nous commençons maintenant à apprendre le proxy Java simple proxy dynamique, il va encore plus loin que l'idée des proxys car il peut créer dynamiquement des proxys et gérer dynamiquement les appels aux méthodes proxy. Tous les appels effectués sur le proxy dynamique sont redirigés vers un seul gestionnaire d'appels, dont le travail consiste à révéler le type d'appel et à déterminer la contre-mesure appropriée. Ci-dessous, nous utilisons des cas pour approfondir notre compréhension des proxys dynamiques Java :

1. Créer un processeur qui hérite d'InvocationHandler : DynamicProxyHandler

package com.huhx.dynamicproxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.Arrays;

public class DynamicProxyHandler implements InvocationHandler {
    private Object proxied;

    public DynamicProxyHandler(Object proxied) {
        System.out.println("dynamic proxy handler constuctor: " + proxied.getClass());
        this.proxied = proxied;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("dynamic proxy name: " + proxy.getClass());
        System.out.println("method: " + method.getName());
        System.out.println("args: " + Arrays.toString(args));
        
        Object invokeObject = method.invoke(proxied, args);
        if (invokeObject != null) {
            System.out.println("invoke object: " + invokeObject.getClass());
        } else {
            System.out.println("invoke object is null");
        }
        return invokeObject;
    }
}
Copier après la connexion

2. Nous écrivons A méthode test Main, DynamicProxyMain :

package com.huhx.dynamicproxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;

import com.huhx.proxy.Interface;
import com.huhx.proxy.RealObject;

public class DynamicProxyMain {
    public static void consumer(Interface iface) {
        iface.getMyName();
        String name = iface.getNameById("1");
        System.out.println("name: " + name);
    }

    public static void main(String[] args) throws Exception, SecurityException, Throwable {
        RealObject realObject = new RealObject();
        consumer(realObject);
        System.out.println("==============================");

        // 动态代理
        ClassLoader classLoader = Interface.class.getClassLoader();
        Class<?>[] interfaces = new Class[] { Interface.class };
        InvocationHandler handler = new DynamicProxyHandler(realObject);
        Interface proxy = (Interface) Proxy.newProxyInstance(classLoader, interfaces, handler);

        System.out.println("in dynamicproxyMain proxy: " + proxy.getClass());
        consumer(proxy);
    }
}
Copier après la connexion

3. Les résultats d'exécution sont les suivants :

my name is huhx
argument id: 1
name: huhx
==============================
dynamic proxy handler constuctor: class com.huhx.proxy.RealObject
in dynamicproxyMain proxy: class com.sun.proxy.$Proxy0
dynamic proxy name: class com.sun.proxy.$Proxy0
method: getMyName
args: null
my name is huhx
invoke object is null
dynamic proxy name: class com.sun.proxy.$Proxy0
method: getNameById
args: [1]
argument id: 1
invoke object: class java.lang.String
name: huhx
Copier après la connexion

À partir des résultats de sortie ci-dessus, nous pouvons tirer les conclusions suivantes :

Le InvocationHandler associé à l'objet proxy exécutera sa méthode d'invocation uniquement lorsque l'objet proxy appelle une méthode

Compréhension des trois paramètres d'invocation : L'objet proxy est l'objet du proxy, La méthode méthode est la classe Method qui appelle la méthode dans l'objet réel, Object[] args sont les paramètres qui appellent la méthode dans l'objet réel

Le principe du proxy dynamique Java

1. Le code clé du proxy dynamique est Proxy.newProxyInstance (classLoader, interfaces, handler). Suivons le code source et jetons un œil :

public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException {
  // handler不能为空
    if (h == null) {
        throw new NullPointerException();
    }

    final Class<?>[] intfs = interfaces.clone();
    final SecurityManager sm = System.getSecurityManager();
    if (sm != null) {
        checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
    }

    /*
     * Look up or generate the designated proxy class.
     */
  // 通过loader和接口,得到代理的Class对象
    Class<?> cl = getProxyClass0(loader, intfs);

    /*
     * Invoke its constructor with the designated invocation handler.
     */
    try {
        final Constructor<?> cons = cl.getConstructor(constructorParams);
        final InvocationHandler ih = h;
        if (sm != null && ProxyAccessHelper.needsNewInstanceCheck(cl)) {
            // create proxy instance with doPrivilege as the proxy class may
            // implement non-public interfaces that requires a special permission
            return AccessController.doPrivileged(new PrivilegedAction<Object>() {
                public Object run() {
                    return newInstance(cons, ih);
                }
            });
        } else {
       // 创建代理对象的实例
            return newInstance(cons, ih);
        }
    } catch (NoSuchMethodException e) {
        throw new InternalError(e.toString());
    }
}
Copier après la connexion
.

2. Jetons un coup d'œil au code source de la méthode newInstance :

private static Object newInstance(Constructor<?> cons, InvocationHandler h) {
    try {
        return cons.newInstance(new Object[] {h} );
    } catch (IllegalAccessException | InstantiationException e) {
        throw new InternalError(e.toString());
    } catch (InvocationTargetException e) {
        Throwable t = e.getCause();
        if (t instanceof RuntimeException) {
            throw (RuntimeException) t;
        } else {
            throw new InternalError(t.toString());
        }
    }
}
Copier après la connexion

3. Lorsque nous appelons une méthode via l'objet proxy, l'appel de cette méthode sera transmis à la méthode d'invocation de l'appel de l'interface InvocationHandler.

Je n'ai pas trouvé le code qui incarne cette phrase dans le code source, j'ai donc ajouté le code suivant à la méthode principale de la classe de test :

if (proxy instanceof Proxy) {
    InvocationHandler invocationHandler = Proxy.getInvocationHandler(proxy);
    invocationHandler.invoke(proxy, realObject.getClass().getMethod("getMyName"), null);
    System.out.println("--------------------------------------");
}
Copier après la connexion

这段代码的输出结果如下,与上述中调用代理对象中的getMyName方法输出是一样的,不知道Jvm底层是否是这样判断的:

dynamic proxy handler constuctor: class com.huhx.proxy.RealObject
dynamic proxy name: class com.sun.proxy.$Proxy0
method: getMyName
args: null
my name is huhx
invoke object is null
--------------------------------------
Copier après la connexion

更多java知识请关注java基础教程栏目。

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!

Étiquettes associées:
source:cnblogs.com
Déclaration de ce site Web
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
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal
À propos de nous Clause de non-responsabilité Sitemap
Site Web PHP chinois:Formation PHP en ligne sur le bien-être public,Aidez les apprenants PHP à grandir rapidement!