Java Dynamic proxy implementation in proxy Mode

Source: Internet
Author: User

Today, I suddenly wanted to see the dynamic proxy of JDK, because I used to know a little about it, and I just wanted to test it, the following interfaces and classes have been written soon:
Interface Class: UserService. java

Copy codeThe Code is as follows: package com. yixi. proxy;
Public interface UserService {
Public int save ();
Public void update (int id );
}

Implementation class: UserServiceImpl. javaCopy codeThe Code is as follows: package com. yixi. proxy;
Public class UserServiceImpl implements UserService {
@ Override
Public int save (){
System. out. println ("user save ....");
Return 1;
}
@ Override
Public void update (int id ){
System. out. println ("update a user" + id );
}
}

Then, when the monkey is in a hurry, write the InvocationHandler you want: this function is very simple, that is, record the start time and end time of method execution.
TimeInvocationHandler. javaCopy codeThe Code is as follows: package com. yixi. proxy;
Import java. lang. reflect. InvocationHandler;
Import java. lang. reflect. Method;
Public class TimeInvocationHandler implements InvocationHandler {
@ Override
Public Object invoke (Object proxy, Method method, Object [] args)
Throws Throwable {
System. out. println ("startTime:" + System. currentTimeMillis ());
Object obj = method. invoke (proxy, args );
System. out. println ("endTime:" + System. currentTimeMillis ());
Return obj;
}
}

All preparations have been completed. Of course, you have to start writing and testing!
Test. javaCopy codeThe Code is as follows: package com. yixi. proxy;
Import java. lang. reflect. Proxy;
Public class Test {
Public static void main (String [] args) {9 TimeInvocationHandler timeHandler = new TimeInvocationHandler ();
UserService u = (UserService) Proxy. newProxyInstance (UserServiceImpl. class. getClassLoader (), UserServiceImpl. class. getInterfaces (), timeHandler );
U. update (2 );
U. save ();
}
}

I ran it happily, but it didn't give you an exception when the screen was full:Copy codeThe Code is as follows: startTime: 1352877835040.
StartTime: 1352877835040
StartTime: 1352877835040
Exception in thread "main" java. lang. reflect. UndeclaredThrowableException
At $ Proxy0.update (Unknown Source)
At com. yixi. proxy. Test. main (Test. java: 11)
Caused by: java. lang. reflect. InvocationTargetException
At sun. reflect. NativeMethodAccessorImpl. invoke0 (Native Method)
At sun. reflect. NativeMethodAccessorImpl. invoke (NativeMethodAccessorImpl. java: 39)
At sun. reflect. DelegatingMethodAccessorImpl. invoke (DelegatingMethodAccessorImpl. java: 25)
At java. lang. reflect. Method. invoke (Method. java: 597)
At com. yixi. proxy. TimeInvocationHandler. invoke (TimeInvocationHandler. java: 12)
... 2 more

Com. yixi. proxy. TimeInvocationHandler. invoke (TimeInvocationHandler. java: 12) exceptions clearly tell the problem of the 12 rows in TimeInvocationHandle: that isCopy codeThe Code is as follows: public Object invoke (Object proxy, Method method, Object [] args)
Throws Throwable {
System. out. println ("startTime:" + System. currentTimeMillis ());
Object obj = method. invoke (proxy, args );
System. out. println ("endTime:" + System. currentTimeMillis ());
Return obj;
}

There are no errors in the method! Because the method is provided in the invoke () method. all the parameters required by invoke (Object, Object []) will be used as appropriate. If you really think that, you will be in the JDK trap, let's take a look at the correct method to prevent some students from looking at the following at least to give a correct solution:
Modify TimeInvocationHandler. javaCopy codeThe Code is as follows: package com. yixi. proxy;
Import java. lang. reflect. InvocationHandler;
Import java. lang. reflect. Method;
Public class TimeInvocationHandler implements InvocationHandler {
Private Object o;
Public TimeInvocationHandler (Object o ){
This. o = o;
}
@ Override
Public Object invoke (Object proxy, Method method, Object [] args)
Throws Throwable {
System. out. println ("startTime:" + System. currentTimeMillis ());
Object obj = method. invoke (o, args );
System. out. println ("endTime:" + System. currentTimeMillis ());
Return obj;
}
}

Modify Test. javaCopy codeThe Code is as follows: package com. yixi. proxy;
Import java. lang. reflect. Proxy;
Public class Test {
Public static void main (String [] args ){
TimeInvocationHandler timeHandler = new TimeInvocationHandler (new UserServiceImpl ());
UserService u = (UserService) Proxy. newProxyInstance (UserServiceImpl. class. getClassLoader (), UserServiceImpl. class. getInterfaces (), timeHandler );
U. update (2 );
U. save ();
}
}

The output result is correct:Copy codeThe Code is as follows: startTime: 1352879531334.
Update a user 2
End Time: 1352879531334
StartTime: 1352879531334
User save ....
End Time: 1352879531335

If you want less code, you can directly write the Anonymous class:
Package com. yixi. proxy;
Import java. lang. reflect. InvocationHandler;
Import java. lang. reflect. Method;
Import java. lang. reflect. Proxy;
Public class Test {
Public static void main (String [] args ){
Final UserServiceImpl usi = new UserServiceImpl ();
UserService u = (UserService) Proxy. newProxyInstance (
Usi. getClass (). getClassLoader (),
Usi. getClass (). getInterfaces (),
New InvocationHandler (){
@ Override
Public Object invoke (Object proxy, Method method, Object [] args)
Throws Throwable {
System. out. println ("startTime:" + System. currentTimeMillis ());
Object obj = method. invoke (usi, args );
System. out. println ("endTime:" + System. currentTimeMillis ());
Return obj;
}
});
U. update (2 );
U. save ();
}
}
Since the first parameter in method. invoke (target, args); is passed in as the target Object, why is the invocationHandler's Invoke method an Object proxy parameter? Let's take a look!
For the most important invoke method (I personally think), let's take a look at what JDK says:Copy codeThe Code is as follows: invoke
Object invoke (Object proxy,
Method method,
Object [] args)
Throws Throwable calls the processing method on the proxy instance and returns the result. When a method is called on the proxy instance associated with the method, the method is called on the call handler.
Parameters:
Proxy-proxy instance on which the method is called
Method-the Method Instance corresponding to the interface method called on the proxy instance. The Method object Declaration class will be the interface in which the Method is declared. This interface can be a superinterface of the proxy interface on which the proxy class inherits the Method.
Args-an array of objects that contain the parameter values of method calls on the proxy instance. If the interface method does not use a parameter, It is null. Parameters of the basic type are encapsulated in an instance of the appropriate basic Wrapper class (such as java. lang. Integer or java. lang. Boolean.

Proxy-the proxy instance on which the method is called? What does this sentence mean? Proxy? Is method a proxy method? Then, should the method for executing the proxy be Object obj = method. invoke (proxy, args? At that time, I didn't turn around. I went to discuss the group, but I didn't find any inspiration when I went to google. Think about it. Let's look at the source code. Maybe we can see something!
Open the source code of the Proxy class and find a constructor:Copy codeThe Code is as follows: protected InvocationHandler h;

Protected Proxy (InvocationHandler h ){
This. h = h;
}

The InvocationHandler is used as the Proxy Constructor's parameter... so what should it do with InvocationHandler? Is there any connection with the invoke () method in InvocationHandler?
The first thing I think of is that the Proxy calls the following statement internally:Copy codeThe Code is as follows: h. invoke (this, methodName, args );

Because you have to call the invoke method to execute the corresponding method,
Let's take a look at this.

Here you will find that it seems like a bit of a feeling: when u. when update (2) is run, the Proxy will call handler. invoke (proxyClass, update, 2) à that is, the proxyClass is called. update (2 );
When u. save (); à Proxy will call handler. invoke (proxyClass, save, null) à that is, proxyClass. save () is called ();

When Test. java is changed to the following:

Copy codeThe Code is as follows: public class Test {
Public static void main (String [] args ){
Final UserServiceImpl usi = new UserServiceImpl ();
UserService u = (UserService) Proxy. newProxyInstance (
Usi. getClass (). getClassLoader (),
Usi. getClass (). getInterfaces (),
New InvocationHandler (){
@ Override
Public Object invoke (Object proxy, Method method, Object [] args)
Throws Throwable {
Return null;
}
});
U. update (2 );
U. save ();
}
}

Note that at this time, the anonymous class method returns null, and you will find:Copy codeThe Code is as follows: Exception in thread "main" java. lang. NullPointerException
At $ Proxy0.save (Unknown Source)
At com. yixi. proxy. Test. main (Test. java: 17)

17 rows of null pointers, that is, the u. save () method has null elements. Is u null? No. If u is null, then u. update (2) there, a null pointer exception will be reported. When I comment out 17 rows, the exception does not indicate u. update () can be executed normally. So why?
In fact, this is why the invoke method returns null:
Note the following two methods in the UserService class:Copy codeThe Code is as follows: public interface UserService {
Public int save ();
Public void update (int id );
}

The Save () method returns the int type while the update method returns the void type. According to the above assumption, handler is returned. invoke () is the implementation of proxyClass. update (2);, the return Method in the invoke method is the return value of the corresponding proxy method,
Therefore, when the invoke method returns null, the proxy's update method receives the return value as null, which is originally a void, so no exception is reported, the proxy save must return the int type value. We still return null. JVM cannot convert null to int type, so an exception is reported.
In this way, the explanation can be explained, and the previous speculation can be proved.
In InvocationHandler, the first parameter proxy in the invoke method seems to be used only to allow the Proxy class to pass in the reference of the proxy object proxyClass when calling the method of the InvocationHandler object.

Literary talents do not work! Limited capabilities! I hope you can correct it...

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.