How a jdk dynamic proxy running

Java dynamic proxy technology is one of the most popular technologies in the Java World. It is applied in many development frameworks, the famous one is Spring IOC. Figuring it out is very necessary.

What does a proxy mean?

A client accesses the methods of the first object by the second object. We call the second object a proxy of the first object. Someone may ask why people do it? One reason that we are going to talk is that people want to do something before or after executing each method of the original object. For example, if you are a doctor, you should sanitize your hands before an operation whatever you think weather your hand is clean or dirty.

What should we do to achieve the goal for an object of a special class?

The proxy pattern can implement the goal easily. You just put the original object into the proxy object as a member, and then creat the same number of methods with same names, which can call the methods of the original object by the member variant. Of course, you can add some code before and after calling original method. You can do it like this:

$OriginalObject {
    method1(){}
    emthod2(){}
    method3(){}
}

$ProxyObject {
    $OriginalObject;
    method1(){
        //Do something before the original method.
        $OriginalObject.mehtod1();
        //Do something after the Original method. 
    }
    method2(){
        //it is the same like method1
    }
    method3(){
        //it is the same like method1.
    }
}

Tips: I don’t use the class to demonstrate them, $ before names means an object. Using objects make it easy to understand the process of calling and omit the extra consideration as a class. I often confuse the distinction between class and object, writing like this is a good way to remind me about that.

You can use the proxy object like this:

$test{
    $ProxyObject.method1();
    $ProxyObject.method2();
    $ProxyObject.method3();
}

In the most cases, you only need to do same things for all methods before or after calling them. If you need to do different things for each method, I don’t think that it is necessary to use proxy technology. In addition, you may hardly know what class an object need to be proxied before using them. So in fact, we need to generate an object dynamically to proxy any objects.

How do we generate an object to proxy any objects?

Actually, Jdk has a class Proxy that can generate a proxy object according to the original object without need a class. It seems quite mysterious. Jdk can not generate an object without a class as well. It only generates a hidden class to create an object. If we can disclose the object of the hidden class, we will figure out the proxy mechanism.

$DynamicProxy = Proxy.newProxyInstance($YourObject.class.getClassLoader(), $YourObject.class.getInterfaces(), $InvocationHandler);

Tips: $InvocationHandler is an object of your implement class of InvocationHandler interface.

Please look at the object of hidden class generated by jdk:

$DynamicaProxy{
    $InvocationHandler;
    method1(){
        $InvocationHandler.invoke(...,$method,...);
    }
    method2(){
        $InvocationHandler.invoke(...,$method,...);
    }
    method3(){
        $InvocationHandler.invoke(...,$method,...):
    }
}

I have ignored many details of the object $DynamicaProxy, and you can see all the methods automatically generated from original object call the same method of a member variant. You must have guessed that the InvocationHandler is an interface which you can implement it to decide what should be executed before or after the original method. Please see the object $invocationHandler.

$InvocationHandler{
    $YourObject
    invoke(...,$method,...){
        //before one of your object executing
        $method.invoke($YourObject,...);
        //After one of your object executing
    }
}

Tip: InvocationHandler is a standard interface in Jdk. The $DynamicaProxy and $InvocationHandler all use the reflection technology of JAVA. you can use the method reflection to call the original method in the $invocation implemented by you. So you do not need to write same Before-After code for all proxy methods.

We can see the whole embed object code like this:

$DynamicaProxy{
    $InvocationHandler{
        $YourObject
        invoke(...,$method,...){
            //before one of your object executing
            $method.invoke($YourObject,...);
            //After one of your object executing
        }
    }
    method1(){
        $InvocationHandler.invoke(...,$method,...);
    }
    method2(){
        $InvocationHandler.invoke(...,$method,...);
    }
    method3(){
        $InvocationHandler.invoke(...,$method,...):
    }
}

How do we implement multiple layer proxy?

We can consider the $DynamicaProxy as your another object and generate another proxy object by Proxy class. Like this:

$DynamicaProxy1 = Proxy.newProxyInstance($DyanmicProxy.class.getClassLoader(), $DynamicProxy.class.getInterfaces(), $InvocationHandler1);

You have to give an object of another implement of InvocationHandler, so you can execute different code in the other layer.

$InvocationHandler1{
    $DynamicProxy1;
    invoke(...$method...){
        //some other things before 
        $method.invoke($DynamicProxy1,...);
       //some other things after  
    }
}

We have fount that we can proxy an object any times and don’t care about the type of the object. In fact, it is not ture, in Jdk, all you want to proxy need come from the same interface.

Ok, let us see all the object embed together.

$DynamicaProxy1{
    $InvocationHandler1{
        $DynamicaProxy{
            $InvocationHandler{
                $YourObject
                invoke(...,$method,...){
                    //before one of your object executing
                    $method.invoke($YourObject,...);
                    //After one of your object executing
                }
            }
            method1(){
                $InvocationHandler.invoke(...,$method,...);
            }
            method2(){
                $InvocationHandler.invoke(...,$method,...);
            }
            method3(){
                $InvocationHandler.invoke(...,$method,...):
            }
        }
        invoke(...,$method,...){
            //before one of your object executing
            $method.invoke($DynamicProxy,...);
            //After one of your object executing
        }
    }
    method1(){
        $InvocationHandler.invoke(...,$method,...);
    }
    method2(){
        $InvocationHandler.invoke(...,$method,...);
    }
    method3(){
        $InvocationHandler.invoke(...,$method,...):
    }
}

At last, you will get the object $DynamicProxy1. we can see the calling order through a picture.

You might also enjoy