Home  >  Article  >  Java  >  Tutorial on implementing dynamic proxy in Java

Tutorial on implementing dynamic proxy in Java

零下一度
零下一度Original
2017-06-30 09:52:451261browse

The following content is partially based on content on the Internet. I would like to express my gratitude to the original author!

The key to realizing dynamic proxy in Java is these two things: Proxy and InvocationHandler. Let’s start with the invoke method in the InvocationHandler interface and briefly explain how Java implements dynamic proxy. N i First, the integrity of the Invoke method is as follows: java code

Public Object Invoke (Object Proxy, Method Method, Object [] ARGS)
Throws Throwable
Tutorial on implementing dynamic proxy in Java
{
  1. method.invoke(obj, args);      

    return 
  2. null;                                      , First of all, guess that Method is the method of calling, that is, the method that needs to be executed; ARGS is the parameter of the method; proxy, what is this parameter? The above implementation of the invoke() method is a relatively standard form. We see that the proxy parameter is not used here. View the description of Proxy in the JDK documentation, as follows:
  3. Java code
  4. A method invocation on a proxy instance through one of its pr oxy interfaces will be dispatched to the invoke method of the instance’s invocation handler, passing the proxy instance, a java.lang.reflect.Method object identifying the method that was invoked, and an array of type Object containing the arguments.

by From this we can know that the above guess is correct, and we also know that the proxy parameter is passed an instance of the proxy class.

For the convenience of explanation, here is a simple example to implement dynamic proxy.
                                                                                                                                
public
interface Subject {

Tutorial on implementing dynamic proxy in Java
    public
  1. void request();

}




Java code Tutorial on implementing dynamic proxy in Java
  1. //Real role: Implemented the Subject’s request() method

  2. public class RealSubject implements Subject{

  3. public void request(){

  4. System.out.println("From real subject.");

  5. }

  6. }


Java code

Tutorial on implementing dynamic proxy in Java
//Implemented InvocationHandler
  1. public
  2. class DynamicSubject
  3. implements In vocationHandler

    {

  4. private Object obj;
  5. //This is the benefit of dynamic proxy. The encapsulated object is of Object type and accepts any type of object.
  6. }

  7. public DynamicSubject(Object obj)
  8. {

  9. this.obj = ob j;

  10. }

  11. // This method is not what we explicitly call
  12. public Object invoke(Object proxy, Method method, Object[] args)

    throws Throwable
  13. {
  14. System.out.println( "before calling " + method);

  15. method.invoke(obj, args); //-----> See the next article for details on this step. Java calls a certain function through the reflection mechanism You will understand the methods of each class after reading them.

  16. System.out.println(
  17. "after calling " + method);
  18. return

    null;

  19. }

  20. )

    1. //Client: generated a proxy instance and called the request() method

    2. public class Client {

    3. public static void main(String [] args) throws Throwable{

    4.                                                          Subject rs=new RealSubject();//Specify the proxy here Class

    5. InvocationHandler ds=
    6. new DynamicSubject(rs);

      Class> cls=rs.getClass();

    7. ​​​​​
    8. //The following is a one-time use Generate proxy

    9.                                                                                                                                                                                   Interfaces(), ds);

    10. /Here it can be proved through the running results that the subject is an instance of Proxy. This instance implements the Subject interface
    11. System.out.println(subject

      instanceof Proxy);

    12.        //Here It can be seen that the subject's Class class is $Proxy0. This $Proxy0 class inherits Proxy and implements the Subject interface.

    13. toString());

    14. System.out.print("The attributes in subject are: "); [] field=subject.getClass() .getDeclaredFields();

    15.                                                                 

    16.             System.out.print(
    17. "n"+
    18. " The methods in subject are: "); ().getDeclaredMethods( );

    19.                                                                
    20. System.out.println(
    21. "n"+

      "subject’s parent class is: "+subject.getClass().getSuperclass());

    22. System. out.print(

      "n"+
    23. "The interface implemented by subject is: ");
    24. Class>[] interfaces=subject.getClass().getInterfaces();

      ​​​
    25. }

    26. System.out.println("nn"+"The operation result is: "); Subject.request();

    27. }
    28. )
    29. The running results are as follows: the package name is omitted here, * **Instead of

true subject’s Class class is: class $Proxy0 The attributes in
subject are: m1, m3, m0, m2,
methods in subject are: request , hashCode, equals, toString,

subject’s parent class is: class java.lang.reflect.Proxy
subject implements the interface: cn.edu.ustc.dynamicproxy.Subject, Tutorial on implementing dynamic proxy in Java
  1. The running result is:
  2. before calling public abstract void ***.Subject.request()
  3. From real subject.
  4. after calling public abstract void ***.Subject.re quest( )
  5. PS: The information of this result is very important, at least to me. Because the root cause of my confusion about dynamic proxy is that I misunderstood the subject.request() above. At least I was confused by the surface. I did not find the connection between the subject and Proxy. I was entangled in the last call of request( ) is connected with invoke(), and how does invoke know that request exists. In fact, the above true and class $Proxy0 can solve many questions. Together with the source code of $Proxy0 mentioned below, it can completely solve the doubts about dynamic proxy.

  6. As you can see from the above code and results, we did not explicitly call the invoke() method, but this method was indeed executed. Let’s analyze the whole process:
  7. From the code in the Client, we can use the newProxyInstance method as a breakthrough. Let’s first take a look at the source code of the newProxyInstance method in the Proxy class:

Java code

  1. public static Object newProxyInstance(ClassLoader loader,  

  2.         Class>[] interfaces,  

  3.         InvocationHandler h)  

  4. throws IllegalArgumentException  

  5. {  

  6.     if (h == null) {  

  7.         throw new NullPointerException();  

  8.     }  

  9.     /* 

  10.      * Look up or generate the designated proxy class. 

  11.      */  

  12.     Class cl = getProxyClass(loader, interfaces);  

  13.     /* 

  14.      * Invoke its constructor with the designated invocation handler. 

  15.      */  

  16.     try {  

  17.            /* 

  18.             * Proxy源码开始有这样的定义: 

  19.             * private final static Class[] constructorParams = { InvocationHandler.class }; 

  20.             * cons即是形参为InvocationHandler类型的构造方法 

  21.            */  

  22.         Constructor cons = cl.getConstructor(constructorParams);  

  23.         return (Object) cons.newInstance(new Object[] { h });  

  24.     } catch (NoSuchMethodException e) {  

  25.         throw new InternalError(e.toString());  

  26.     } catch (IllegalAccessException e) {  

  27.         throw new InternalError(e.toString());  

  28.     } catch (InstantiationException e) {  

  29.         throw new InternalError(e.toString());  

  30.     } catch (InvocationTargetException e) {  

  31.         throw new InternalError(e.toString());  

  32.     }  

  33. }  



Proxy.newProxyInstance(ClassLoader loader, Class>[] interfaces, InvocationHandler h) does the following things.
(1) According to the parameters loader and interfaces calling method getProxyClass(loader, interfaces) creates the proxy class $Proxy0. The $Proxy0 class implements the interfaces interface and inherits the Proxy class.
                                (2) Instantiate $Proxy0 and pass the DynamicSubject in the constructor, and then call $Proxy0 The constructor of the parent class Proxy assigns a value to h as follows:

Java code Tutorial on implementing dynamic proxy in Java
  1. class Proxy{

  2. InvocationHandler h=null;

  3. protected Proxy(InvocationHandler h) {

  4. }

  5. ...

  6. }

Let’s take a look at the source code of $Proxy0 which inherits Proxy:


Java code

  1. public final class $Proxy0 extends Proxy implements Subject {  

  2.     private static Method m1;  

  3.     private static Method m0;  

  4.     private static Method m3;  

  5.     private static Method m2;  

  6.     static {  

  7.         try {  

  8.             m1 = Class.forName("java.lang.Object").getMethod("equals",  

  9.                     new Class[] { Class.forName("java.lang.Object") });  

  10.             m0 = Class.forName("java.lang.Object").getMethod("hashCode",  

  11.                     new Class[0]);  

  12.             m3 = Class.forName("***.RealSubject").getMethod("request",  

  13.                     new Class[0]);  

  14.             m2 = Class.forName("java.lang.Object").getMethod("toString",  

  15.                     new Class[0]);  

  16.         } catch (NoSuchMethodException nosuchmethodexception) {  

  17.             throw new NoSuchMethodError(nosuchmethodexception.getMessage());  

  18.         } catch (ClassNotFoundException classnotfoundexception) {  

  19.             throw new NoClassDefFoundError(classnotfoundexception.getMessage());  

  20.         }  

  21.     } //static  

  22.     public $Proxy0(InvocationHandler invocationhandler) {  

  23.         super(invocationhandler);  

  24.     }  

  25.     @Override  

  26.     public final boolean equals(Object obj) {  

  27.         try {  

  28.             return ((Boolean) super.h.invoke(this, m1, new Object[] { obj })) .booleanValue();  

  29.         } catch (Throwable throwable) {  

  30.             throw new UndeclaredThrowableException(throwable);  

  31.         }  

  32.     }  

  33.     @Override  

  34.     public final int hashCode() {  

  35.         try {  

  36.             return ((Integer) super.h.invoke(this, m0, null)).intValue();  

  37.         } catch (Throwable throwable) {  

  38.             throw new UndeclaredThrowableException(throwable);  

  39.         }  

  40.     }  

  41.     public final void request() {  

  42.         try {  

  43.             super.h.invoke(this, m3, null);  

  44.             return;  

  45.         } catch (Error e) {  

  46.         } catch (Throwable throwable) {  

  47.             throw new UndeclaredThrowableException(throwable);  

  48.         }  

  49.     }  

  50.     @Override  

  51.     public final String toString() {  

  52.         try {  

  53.             return (String) super.h.invoke(this, m2, null);  

  54.         } catch (Throwable throwable) {  

  55.             throw new UndeclaredThrowableException(throwable);  

  56.         }  

  57.     }  

  58. }  



Then cast the obtained $Proxy0 instance into Subject and assign the reference to subject. When the subject.request() method is executed, the request() method in the $Proxy0 class is called, and then the invoke() method of h in the parent class Proxy is called. That is, InvocationHandler.invoke().

PS: 1. One thing that needs to be explained is that the getProxyClass method in the Proxy class returns the Proxy Class class. The reason why I explain this is because I made a low-level mistake at the beginning, thinking that what was returned was the "Class of the proxied class" - -! It is recommended to take a look at the source code of getProxyClass, it is very long =. =
2. It can be seen from the source code of $Proxy0 that the dynamic proxy class not only proxies the methods in the explicitly defined interface, but also proxies the inherited equals() and hashcode() in the java root class Object. , toString(), and only these three methods.

Q: Until now, there is still a question. The first parameter in the invoke method is an instance of Proxy (to be precise, the instance of $Proxy0 is ultimately used), but what is its use? In other words, how does the program show its effect?
A: From my current level, this proxy parameter has no effect. In the entire dynamic proxy mechanism, the proxy parameter of the invoke method in InvocationHandler is not used. The parameter passed in is actually an instance of the proxy class. I think it may be to allow programmers to use reflection in the invoke method to obtain some information about the proxy class.

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

Statement:
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