It's a chance today. I suddenly wanted to see the JDK's dynamic proxies, because I knew a little about it before, and simply wanted to test it, and soon it was written with so many interfaces and classes:
Interface class: Userservice.java
Copy Code code as follows:
Package com.yixi.proxy;
Public interface UserService {
public int Save ();
public void update (int id);
}
Implementation class: Userserviceimpl.java
Copy Code code 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 the monkey anxious to write their own Invocationhandler: This function is very simple is to record the start time and end time of the method execution
Timeinvocationhandler.java
Copy Code code 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 the preparations are ready, of course, to start writing tests!
Test.java
Copy Code code 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 ();
}
}
Run it cheerfully, but it doesn't give you face. The result is a full screen exception:
Copy Code code as follows:
starttime:1352877835040
starttime:1352877835040
starttime:1352877835040
Exception in thread "main" java.lang.reflect.UndeclaredThrowableException
At $Proxy 0.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) The anomaly clearly tells the question of 12 lines in Timeinvocationhandle: that is
Copy Code code 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 is nothing wrong with the method. Because in the invoke () This method appears to provide Method.invoke (object,object[]) All the parameters, we will take it for granted, if you really think so you will be in the JDK trap, read the correct way first Prevent some students are not in the mood to look at the back of at least a correct solution:
Modify Timeinvocationhandler.java
Copy Code code 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.java
Copy Code code 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 ();
}
}
Now is the correct output result:
Copy Code code as follows:
starttime:1352879531334
Update a User 2
endtime:1352879531334
starttime:1352879531334
User save ....
endtime:1352879531335
If you want to have less code, you can write anonymous classes directly:
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 argument in Method.invoke (Target,args) is the target object, then the Invocationhandler invoke method needs an object proxy parameter. Let's look down!
For the most important method of invoke (personally feel) let's see what the JDK says:
Copy Code code as follows:
Invoke
Object Invoke (Object proxy,
Method,
Object[] args)
Throws Throwable handles the method call on the proxy instance and returns the result. This method is called on the calling handler when the method is invoked on the proxy instance associated with the method.
Parameters:
Proxy-Invokes an instance of the method on it
Method-corresponds to an instance of an interface that is invoked on the proxy instance. The Declaration class of the method object will be the interface in which the methods are declared, which can be the interface of the proxy interface that the proxy class relies on to inherit the method.
Args-an array of objects containing the parameter values of the method call on the incoming proxy instance, or null if the interface method does not use parameters. The parameters of the base type are wrapped in an instance of the appropriate base wrapper class (such as Java.lang.Integer or Java.lang.Boolean).
Proxy-invokes the delegate instance of the method on it? What do you mean by that remark? Agent? method is the proxy approach? So the method of executing the agent is not supposed to be object obj = Method.invoke (proxy, args); At that time I did not turn the corner, to discuss groups, to Google did not find any inspiration, think or this look at the source code may be able to see something!
Open the proxy class source to find out how a construction method:
Copy Code code as follows:
protected Invocationhandler H;
Protected Proxy (Invocationhandler h) {
This.h = h;
}
To use Invocationhandler as the parameter of the construction method of the proxy .... What's it going to do with Invocationhandler? Is there any connection to the invoke () method in Invocationhandler?
My first thought was that the following statement would be invoked within the proxy:
Copy Code code as follows:
H.invoke (This,methodname,args);
Because you have to invoke the Invoke method to perform the corresponding method,
We'll take a look at this.
Here you will find it seems a bit of a feeling: when U.update (2) Àproxy will call Handler.invoke (proxyclass,update,2) à that is called proxyclass.update (2);
When U.save (), the àproxy invokes Handler.invoke (proxyclass,save,null) à, which is called proxyclass.save ();
When Test.java changed to this:
Copy Code code 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 the method of the anonymous class at this time returns NULL, and when you run it you will find that:
Copy Code code as follows:
Exception in thread "main" java.lang.NullPointerException
At $Proxy 0.save (Unknown Source)
At Com.yixi.proxy.Test.main (test.java:17)
17 lines with null pointers and here's The U.save () method has null element is it that u is empty? I don't think so. If you are null then U.update (2) There will be a null pointer exception, when I have 17 lines commented out After the exception did not explain u.update () normal execution. So what is this all about?
This is actually the reason the Invoke method returns null:
Note the two methods in the UserService class:
Copy Code code as follows:
Public interface UserService {
public int Save ();
public void update (int id);
}
The Save () method returns an int and the Update method returns a void type; According to the above Guess Handler.invoke () is the implementation of proxyclass.update (2); The return method in the Invoke method is the returned value of the corresponding proxy method.
So when the Invoke method returns null, the agent's Update method receives the return value of NULL, and it would have returned void so that it did not report an exception, and agent save must return a numeric value of type int we're returning null. The JVM failed to convert null to int so it was reported as abnormal.
This explains the explanation, and it can be compared to the previous guesses.
The first parameter proxy in the Invoke method in Invocationhandler seems to pass in a reference to the proxy object Proxyclass just so that the proxy class can call the method on the reference of its own Invocationhandler object. To complete the business Proxyclass needs to complete.
Literary talent is not good! Limited Ability! I hope you will correct me.