How the invoke method in java Dynamic proxy is automatically called

Source: Internet
Author: User

I. Differences between dynamic proxy and static proxy. (1) The Proxy class code is fixed and won't be huge because of the increasing size of the business; (2) AOP programming can be implemented, which cannot be implemented by the static Proxy; (3) decoupling, for web services, you can separate the data layer from the business layer. (4) the advantage of dynamic proxy is non-intrusive code extension. The static proxy mode itself has a big problem. If the number of class methods is increasing, the amount of code for the proxy class is very large. Therefore, dynamic proxies are introduced to solve such problems.

Ii. Dynamic proxy

The key to implementing dynamic Proxy in Java is Proxy and InvocationHandler. The following describes how to implement dynamic Proxy in Java by starting with the invoke method in the InvocationHandler interface.
First, the complete form of the invoke method is as follows:

Java code
  1. Public Object invoke (Object proxy, Method method, Object [] args) throws Throwable
  2. {
  3. Method. invoke (obj, args );
  4. Return null;
  5. }
    First, let's guess that method is the method called, that is, the method to be executed; args is the method parameter; proxy, what is this parameter? The above implementation of the invoke () method is a standard form. We can see that the proxy parameter is not used here. View the Proxy instructions in the JDK documentation as follows:
    Java code
    1. A method invocation on a proxy instance through one of its proxy 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.
      From this we can know that the above Guesses are correct, and we also know that the proxy parameter is passed to the proxy class instance.

      For convenience, here is a simple example to implement dynamic proxy.

      Java code
      1. // Abstract role (Dynamic proxy can only be a proxy Interface)
      2. Public interface Subject {
      3. Public void request ();
      4. }
        Java code
        1. // Real role: implements the Subject request () method.
        2. Public class RealSubject implements Subject {
        3. Public void request (){
        4. System. out. println ("From real subject .");
        5. }
        6. }
          Java code
          1. // Implements InvocationHandler
          2. Public class DynamicSubject implements InvocationHandler
          3. {
          4. Private Object obj; // This is the benefit of dynamic proxy. The encapsulated Object is of the Object type and can be any type of Object.
          5. Public DynamicSubject ()
          6. {
          7. }
          8. Public DynamicSubject (Object obj)
          9. {
          10. This. obj = obj;
          11. }
          12. // This method is not displayed for calling
          13. Public Object invoke (Object proxy, Method method, Object [] args) throws Throwable
          14. {
          15. System. out. println ("before calling" + method );
          16. Method. invoke (obj, args );
          17. System. out. println ("after calling" + method );
          18. Return null;
          19. }
          20. }
            Java code
            1. // Client: generates a proxy instance and calls the request () method.
            2. Public class Client {
            3. Public static void main (String [] args) throws Throwable {
            4. // TODO Auto-generated method stub
            5. Subject rs = new RealSubject (); // The proxy class is specified here.
            6. InvocationHandler ds = new DynamicSubject (rs );
            7. Class Cls = rs. getClass ();
            8. // The following is a one-time generation Proxy:
            9. Subject subject = (Subject) Proxy. newProxyInstance (
            10. Cls. getClassLoader (), cls. getInterfaces (), ds );
            11. // The running result shows that the subject is an instance of the Proxy. This instance implements the Subject interface.
            12. System. out. println (subject instanceof Proxy );
            13. // Here we can see that the Class of subject is $ Proxy0. This $ Proxy0 Class inherits the Proxy and implements the Subject interface.
            14. System. out. println ("the Class of subject is:" + subject. getClass (). toString ());
            15. System. out. print ("attributes in subject are :");
            16. Field [] field = subject. getClass (). getDeclaredFields ();
            17. For (Field f: field ){
            18. System. out. print (f. getName () + ",");
            19. }
            20. System. out. print ("\ n" + "methods in subject include :");
            21. Method [] method = subject. getClass (). getDeclaredMethods ();
            22. For (Method m: method ){
            23. System. out. print (m. getName () + ",");
            24. }
            25. System. out. println ("\ n" + "subject's parent class is:" + subject. getClass (). getSuperclass ());
            26. System. out. print ("\ n" + "subject :");
            27. Class [] Interfaces = subject. getClass (). getInterfaces ();
            28. For (Class I: interfaces ){
            29. System. out. print (I. getName () + ",");
            30. }
            31. System. out. println ("\ n" + "running result :");
            32. Subject. request ();
            33. }
            34. }
              Xml Code
              1. The running result is as follows: the package name is omitted here, which is replaced ***.
              2. True
              3. The subject Class is: class $ Proxy0
              4. Attributes in subject include m1, m3, m0, m2,
              5. Methods In subject include: request, hashCode, equals, toString,
              6. Subject's parent class is: class java. lang. reflect. Proxy
              7. The subject implementation interface is: cn.edu. ustc. dynamicproxy. Subject,
              8. The running result is:
              9. Before calling public abstract void ***. Subject. request ()
              10. From real subject.
              11. After calling public abstract void ***. Subject. request ()

                PS: The result information is very important, at least for me. Because the root cause of my dizzy behavior on the dynamic proxy is to apply the above subject. the request () is wrong. At least it is confused by the surface. No connection is found between this subject and the Proxy. At one time, It is entangled in how the request () is called and invoke () contact, and how does invoke know that the request exists. In fact, the above true and class $ Proxy0 can solve a lot of questions, coupled with the $ Proxy0 source code to be discussed below, can completely solve the problem of dynamic proxy.

                From the above Code and results, we can see that the invoke () method is not displayed, but this method is indeed executed. The entire process is analyzed as follows:

                From the code in the Client, we can take the newProxyInstance method as a breakthrough. Let's 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. * The Proxy source code is defined as follows:
                19. * Private final static Class [] constructorParams = {InvocationHandler. class };
                20. * Cons is the constructor of the InvocationHandler type.
                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.
                  (1) create a Proxy class $ Proxy0. $ Proxy0 Class Based on the getProxyClass (loader, interfaces) Call methods of the loader and interfaces parameters to implement the interfaces interface and inherit the Proxy class.
                  (2) instantiate $ Proxy0 and pass DynamicSubject to the constructor In the constructor method. Then $ Proxy0 calls the constructor of the parent class Proxy and assigns a value to h, as shown below:
                  Java code
                  1. Class Proxy {
                  2. InvocationHandler h = null;
                  3. Protected Proxy (InvocationHandler h ){
                  4. This. h = h;
                  5. }
                  6. ...
                  7. }

                    Let's take a look at the source code that inherits the $ Proxy0 of 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, convert the obtained $ Proxy0 instance to Subject and assign the reference to subject. When subject. the request () method in the $ Proxy0 class is called, and the invoke () method of h in the parent class Proxy is called. that is, InvocationHandler. invoke ().

                      PS: 1. Note that the getProxyClass method in the Proxy Class returns the Proxy Class. The reason for this is that I first made a low-level error and thought that the returned Class was "Class under the proxy Class "--! It is recommended that you take a look at the source code of getProxyClass, which is very long =. =
                      2. From the source code of $ Proxy0, we can see that the dynamic proxy class not only proxy the methods in the display defined interface, but also proxies the inherited equals () in the java root class Object (), hashcode (), toString (), and only the three methods.

                      Q: so far, I have another question: the first parameter in the invoke method is the Proxy instance (to be precise, the $ Proxy0 instance is used in the end). But what is the purpose? In other words, how does one display the function in the program?
                      A: As far as my current level is concerned, this proxy parameter does not play A role. In the entire dynamic proxy mechanism, the proxy parameter of the InvocationHandler method is not used. The input parameter 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.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.