In-depth analysis of JDK dynamic proxy (proxy, invocationhandler)

Source: Internet
Author: User

 

Create a proxy object and Test

Public ClassProxytest_old {

Public Static VoidMain (string [] ARGs ){

Userdao =NewUserdaoimpl ();

Loghandler_old loghandler =NewLoghandler_old (userdao );

Userdao userdaproxy = (userdao) proxy.Newproxyinstance(Userdao

. Getclass (). getclassloader (), userdao. getclass ()

. Getinterfaces (), loghandler );

Userdaproxy. Delete (NewUser ());

Userdaproxy. Save (NewUser ());

Userdaproxy. Update (NewUser ());

}

}

Explanation:

1. Proxy is a dynamic proxy class;

2. static object newproxyinstance (classloader loader, class [] interfaces, invocationhandler h): return an instance of the proxy class. The returned proxy class can be used as the proxy class;

It has three parameters:

Classloader loader ---- specifies the class loader of the proxy object

Class [] interfaces ---- specifies the interface of the event because the proxy object is used.

Invocationhandler H ---- specifies the invocationhandler object to be called

3. Implement the loghandler_old object of the invocationhandler Interface

The invoke () method of this object is the actual implementation of the abstract methods of the interface classes proxy this dynamic proxy class;

It has three parameters:

Object proxy ----- proxy object

Method method ----- method of the proxy object (this is not an abstract method of the interface, but a method in the specific implementation class)

Object [] ARGs ----- parameter array of this method

 

In JDK, how does one generate a specific dynamic proxy class?

1. Generate proxy class $ proxy0 class

The proxy. newproxyinstance (classloader loader, class [] interfaces, invocationhandler H) is executed)

The $ proxy0 class is generated. It inherits the proxy object and implements all interfaces of the proxy class according to the second parameter, naturally, all methods to be implemented by the interface can be generated (hashcode, tostring, and equals will be rewritten at this time), but there is no specific implementation body;

2. Load the proxy class $ proxy0 to JVM.

At this time, according to the first parameter of proxy. newproxyinstance (classloader loader, class [] interfaces, invocationhandler H)-The class loader of the proxy class, loads the current proxy class to the JVM.

3. Create a proxy class $ proxy0 Class Object

$ Proxy0 (invocationhandler) constructor of the $ proxy0 class called to generate $ proxy0 class objects

The parameter is the third parameter of proxy. newproxyinstance (classloader loader, class [] interfaces, invocationhandler H ).

This parameter is our own invocationhandler object. We know that the invocationhandler object is combined with the Implementation class of the interface class of the proxy. Therefore, $ the proxy0 object calls the invoke () method of the invocationhandler object to call all methods of interfaces to be implemented;

4. Generate the Class byte of the proxy class

The dynamic proxy generates binary class bytecode.

,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,

Dynamic proxy is the basis of many frameworks and technologies. Spring's AOP implementation is based on dynamic proxy. Understanding the dynamic proxy mechanism is helpful for understanding the underlying implementation of AOP.

The design of the proxy class uses the design idea of the proxy mode. The proxy class Object implements all interfaces of the proxy target, and replaces the target object for actual operations. However, this substitution is not a simple alternative, and it does not make any sense. The proxy aims to enhance the method of the target object, the essence of this enhancement is usually to intercept the method of the target object. Therefore, the proxy should include a method Interceptor to indicate what to do when the method call is intercepted. Invocationhandler is the interceptor interface.

The invocationhandler interface is also in Java. Lang. reflec

ObjectInvoke(Object proxy,
Method method,
Object [] ARGs)

This interface has three parameters, including the second and third parameters. One is the intercepted method and the other is the parameter list of the method. The key is the first parameter. According to the doc document,

Proxy-the proxy instance that the method was invoked on

That is to say, the proxy should be a proxy instance, but why should this parameter be passed in?

With this problem, I compiled a small program for a test.

///////////////////////////////////////

Public interface ianimal {
Void Info ();
}

////////////////////////////////////

Public class dog implements ianimal

{

Public void Info (){
System. Out. println ("I am a dog! ");
}
}

///////////////////////////////////////
Import java. Lang. Reflect .*;

Public class proxytest {
Public static void main (string [] ARGs) throws interruptedexception {
Final ianimal animal = new dog ();
Object proxyobj = proxy. newproxyinstance (
Animal. getclass (). getclassloader (),
Animal. getclass (). getinterfaces (),
New invocationhandler ()
{
Public object invoke (Object proxy, method, object [] ARGs)
{
Try {
System. Out. println ("blocked method:" + method. getname ());
Return method. Invoke (animal, argS );
}
Catch (illegalargumentexception e ){
// Todo auto-generated Catch Block
E. printstacktrace ();
Return NULL;
} Catch (illegalaccessexception e ){
// Todo auto-generated Catch Block
E. printstacktrace ();
Return NULL;
} Catch (invocationtargetexception e ){
// Todo auto-generated Catch Block
E. printstacktrace ();
Return NULL;
}
}
});
If (proxyobj instanceof ianimal)
{
System. Out. println ("The proxyobj is an animal! ");
}
Else
{
System. Out. println ("The proxyobj isn't an animal! ");
}

If (proxyobj instanceof dog)
{
System. Out. println ("The proxyobj is a dog! ");
}
Else
{
System. Out. println ("The proxyobj isn't a dog! ");
}

Ianimal animalproxy = (ianimal) proxyobj;
Animalproxy.info ();
Animalproxy. hashcode ();
System. Out. println (animalproxy. getclass (). getname (). tostring ());
}
}

The execution result of the program is as follows:

The proxyobj is an animal!
The proxyobj isn't a dog!
Method intercepted: info
I am a dog!
Blocked method: hashcode
$ Proxy0

The result shows the following points:

1. proxyobj is an object that implements the target object interface, but different from the target object. That is to say, this proxy mechanism is interface-oriented, not class-oriented.

2. the info method (in the interface) is successfully intercepted, and the hashcode method is also successfully intercepted, but unexpectedly, the getclass method (inherited from the object class method) not intercepted !!

3. Application debugging also shows that the proxy parameter passed in by the invoke method in the invocation interface is indeed the proxy object instance proxyobj

Why is getclass () not intercepted? What is the proxy parameter used?

No matter what, do a test. Since this proxy parameter is a proxy instance object, it is of course the same as proxyobj and can call methods such as info. So we can add the following statement in the invoke method:

(Ianimal) proxy). Info ();

The result is:

The proxyobj is an animal!
The proxyobj isn't a dog!
Method intercepted: info
Method intercepted: info

.......

Method intercepted: info
Method intercepted: info

Then there is stack overflow.

The result is obvious. Calling the method in proxy in the invoke method will trigger the invoke method again, which is stuck in an endless loop. The final result is of course stack overflow.

You can call proxy. getclass () in the invoke method, and the program can run normally. However, calling the hashcode () method also causes stack overflow.

Through the above experiment, we can draw some preliminary conclusions that the proxy parameter in the invoke interface cannot be used to call the method of the implemented interface. The strange thing is that the hashcode () and getclass () methods are inherited from the object. Why can't one be the other? Take a look at the two methods in the object in the doc document and find that getclass () is defined as final, while hashcode () is not. Is this the reason, so I found a non-final method, such as equals, which will cause stack overflow. I found another final method, such as wait () and tried it, invoke does not intercept. Final
Is it the key?

Another question is, what is the use of proxy? Since the proxy can call the getclass () method, we can obtain the class image of the proxy, so that we can obtain all the class information about the proxy instance, such as the method list and annotation, this provides us with a powerful tool to analyze proxy, such as the declarative transaction requirements of the annotation analysis method. I want to input the proxy parameter.

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.