Talk JDK dynamic proxy principle

What is a proxy

Providing a proxy to control access to the object to other objects. In some cases, an object is not suitable or not directly refer to another object, the proxy object can play the role of intermediary between the client and the target audience. - from Baidu Encyclopedia

More simply, it is that we live in mediation

What is the dynamic agent

Dynamic agent operating by reflection at the bytecode runtime to dynamically create the byte code files , and thus create a proxy object.

Not much to say, the first on the code

  • Create an interface:
public interface OutInfo {
    void printInfo();
}
  • Creating the implementation class:
public class Person implements OutInfo {
    private String name;
    private Integer age;

    public Person(String name, Integer age) {
        this.name = name;
        this.age = age;
    }

    @Override
    public void printInfo() {
        System.out.println(name + "..." + age);
    }
}
  • Write dynamic proxy demo
import java.lang.reflect.Proxy;

public class DynamicProxy {
    public static void main(String[] args) {
        Person person = new Person("张三", 23);
        OutInfo oi = (OutInfo) Proxy.newProxyInstance(
                Person.class.getClassLoader(), 
                Person.class.getInterfaces(),
                /*
                 * 此代码基于JDK8编写,所以用到了Lambda表达式
                 */
                (proxy, method, arg) -> {
                    System.out.println("方法前处理");
                    /*
                     * 注意:invoke()的第一个参数只能写被代理对象的实例
                     *  不能写参数proxy,否则会栈溢出,原因后面讲解
                     */
                    Object ret = method.invoke(person, arg);
                    System.out.println("方法后处理");
                    return ret;
                }
        );
        oi.printInfo();
    }
}

Look at the results:
operation result

Looking at the results from the operation, the result of the agent is no problem. So, what is the agent process like?

Acting Process Analysis

Said before the dynamic proxy is to create a dynamic proxy object by operating bytecode, then we look at it generates bytecode files inside some what:

Available through the following code to bytecode files dynamically generated proxy, but requires a separate JRE can, ah! Recommended JDK8! ! !

public void saveProxyClassFile(){
    // 参数:(生成的字节吗对象的名字,被代理对象实现的接口数组)
    byte[] bytes = ProxyGenerator.generateProxyClass("$Proxy", new Class[]{OutInfo.class});
    try(
            FileOutputStream fos =new FileOutputStream(new File("$Proxy.class"))
    ){
        fos.write(bytes);
        fos.flush();
    }catch (Exception e) {
        e.printStackTrace();
    }
}

This is translated by the idea comes decompiler content:

public final class $Proxy extends Proxy implements OutInfo {
    private static Method m1;
    private static Method m3;
    private static Method m2;
    private static Method m0;

    public $Proxy(InvocationHandler var1) throws  {
        super(var1);
    }

    public final boolean equals(Object var1) throws  {
        try {
            return (Boolean)super.h.invoke(this, m1, new Object[]{var1});
        } catch (RuntimeException | Error var3) {
            throw var3;
        } catch (Throwable var4) {
            throw new UndeclaredThrowableException(var4);
        }
    }

    public final void printInfo() throws  {
        try {
            super.h.invoke(this, m3, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final String toString() throws  {
        try {
            return (String)super.h.invoke(this, m2, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final int hashCode() throws  {
        try {
            return (Integer)super.h.invoke(this, m0, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    static {
        try {
            m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
            m3 = Class.forName("ann.study.OutInfo").getMethod("printInfo");
            m2 = Class.forName("java.lang.Object").getMethod("toString");
            m0 = Class.forName("java.lang.Object").getMethod("hashCode");
        } catch (NoSuchMethodException var2) {
            throw new NoSuchMethodError(var2.getMessage());
        } catch (ClassNotFoundException var3) {
            throw new NoClassDefFoundError(var3.getMessage());
        }
    }
}

By reading the translated code, we can know the variables m3 saved is a method object interface, and the proxy method generated printInfo()in such a line of code:

super.h.invoke(this, m3, (Object[])null);

Where, h is what we use Lambda expressions passed in anonymous object, and the role of this method is to call us overridden invoke()method.

In fact, this method is like this:

public Object invoke(Object proxy, Method method, Object[] args)

After the parameter correspondence, we will know the role of proxy parameters, and the dynamic proxy demo in method.invoke(person, arg)written proxy can cause a stack overflow of reasons:

> 递归调用引起了死循环,程序无法结束循环,所以会报栈溢出异常

Through this mechanism, JDK dynamic proxy will be completed

in conclusion

  1. Dynamic proxies are used to generate the proxy objects by manipulating byte code file, this would resolve the static agent to generate proxy classes are many and difficult maintenance problems
  2. Dynamic proxies in some pit, for example:
    1. JDK is required dynamic proxy proxy class must implement the interface, the proxy object is returned to the implementation class interface; if the interface does not want to implement, may be used cglib
    2. In the implementation InvocationHandler interface rewrite incvoke()time method, pay attention to method.invoke()the first argument passed to the proxy object, can not pass rewrite the invoke()first argument, the argument is that because the proxy object.

This is the first time bloggers to write blog posts and content in the wrong place also please correct me comment, but I hope you bear with me. Finally, thank you for reading my blog post.

Guess you like

Origin www.cnblogs.com/ann-zhgy/p/11610765.html