Maison >Java >JavaBase >Le principe du proxy dynamique Java

Le principe du proxy dynamique Java

尚
avant
2019-11-29 17:06:402063parcourir

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.

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

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.

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

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

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);
}

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";
    }
}

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);
    }
}

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()));
    }
}

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

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;
    }
}

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);
    }
}

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

À 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());
    }
}
.

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());
        }
    }
}

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("--------------------------------------");
}

这段代码的输出结果如下,与上述中调用代理对象中的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
--------------------------------------

更多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!

Déclaration:
Cet article est reproduit dans:. en cas de violation, veuillez contacter admin@php.cn Supprimer