Home > Java > JavaBase > body text

The principle of Java dynamic proxy

Release: 2019-11-29 17:06:40
forward
1964 people have browsed it

The principle of Java dynamic proxy

The emergence of Java dynamic proxy mechanism allows Java developers to dynamically obtain proxy classes without manually writing proxy classes. They can simply specify a set of interfaces and delegate class objects. (Recommended: java video tutorial)

The proxy class will be responsible for dispatching all method calls to the delegate object for reflection execution. During the dispatch execution process, developers can also adjust as needed Delegate class objects and their functions, this is a very flexible and flexible proxy framework. Next we start learning about dynamic agents.

Brief description of dynamic proxy

In the dynamic proxy mechanism of java, there are two important classes or interfaces, one is InvocationHandler( Interface), the other is Proxy (Class).

1. Description of 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.
Copy after login

Every dynamic proxy class must implement the InvocationHandler interface, and each proxy class instance is associated with When we reach a handler, when we call a method through the proxy object, the call of this method will be forwarded to be called by the invoke method of the InvocationHandler interface. Let’s take a look at the only method of the InvocationHandler interface, the invoke method:

Object invoke(Object proxy, Method method, Object[] args) throws Throwable
Copy after login

This method receives three parameters and returns an Object type. Their respective meanings are as follows:

proxy: refers to The real object we are proxying for

method: refers to the Method object we want to call the method of the real object

args: refers to the parameters received when calling a method of the real object The Object returned by parameter

refers to the return type of the real object method. The above will be understood in depth in the following examples.

the value to return from the method invocation on the proxy instance.
Copy after login

2. Description of Proxy (Class):

Proxy provides static methods for creating dynamic proxy classes and instances, and it is also the superclass of all dynamic proxy classes created by those methods.

The function of Proxy class is to dynamically create a proxy object. We often use the newProxyInstance method:

public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces,  InvocationHandler h)  throws IllegalArgumentException
Copy after login

Understanding of parameters:

// 一个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
Copy after login

Understanding of return results: An instance of a proxy object

a proxy instance with the specified invocation handler of a proxy class that is defined by the specified class loader and that implements the specified interfaces

Simple Java proxy

We create a Java project for testing and understanding of dynamic proxy, The project structure is as follows:

The principle of Java dynamic proxy

# 1. First define an interface Interface and add two methods.

package com.huhx.proxy;

public interface Interface {
    void getMyName();

    String getNameById(String id);
}
Copy after login

2. Define a real class that implements the above interface, 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";
    }
}
Copy after login

3. Define a proxy object, which is also implemented The above Interface interface:

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);
    }
}
Copy after login

4. SimpleMain In the Main method, test the above results:

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

5. The running results are as follows :

my name is huhx
argument id: 1
name: huhx
========================================================
proxy getmyname
my name is huhx
proxy getnamebyid
argument id: 1
name: huhx
Copy after login

Java’s dynamic proxy

After completing the above simple Java proxy, now we start to learn Java’s dynamic proxy, It goes one step further than the idea of ​​proxies because it can dynamically create proxies and dynamically handle calls to the proxied methods. All calls made on the dynamic proxy are redirected to a single call handler, whose job is to reveal the type of call and determine the appropriate countermeasure. Below we use cases to deepen our understanding of Java dynamic proxies:

1. Create a processor that inherits 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;
    }
}
Copy after login

2. We write A test Main method, 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);
    }
}
Copy after login

3. The running results are as follows:

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
Copy after login

From the above output results, we can draw the following conclusions:

The InvocationHandler associated with the proxy object will execute its invoke method only when the proxy object calls a method.

Understanding of the three parameters of invoke: Object proxy is the object of the proxy, Method method is the Method class that calls the method in the real object, Object[] args is the parameters of the method that is called in the real object

The principle of Java dynamic proxy

1. The key code of dynamic proxy is Proxy.newProxyInstance(classLoader, interfaces, handler). Let’s follow the source code and take a look:

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

2. Let’s take a look Source code of newInstance method:

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

3. When we call a method through the proxy object, the call of this method will be forwarded to the invoke method of the InvocationHandler interface. transfer.

I couldn’t find the code that reflected this sentence in the source code, so I added the following code to the main method of the test class:

if (proxy instanceof Proxy) {
    InvocationHandler invocationHandler = Proxy.getInvocationHandler(proxy);
    invocationHandler.invoke(proxy, realObject.getClass().getMethod("getMyName"), null);
    System.out.println("--------------------------------------");
}
Copy after login

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

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

The above is the detailed content of The principle of Java dynamic proxy. For more information, please follow other related articles on the PHP Chinese website!

Related labels:
source:cnblogs.com
Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template
About us Disclaimer Sitemap
php.cn:Public welfare online PHP training,Help PHP learners grow quickly!