Dynamic agent, the word in the Java world is often mentioned, especially for the part (here the emphasis on "part" of the word, because there is a year or two to become the great God, the strength of the heinous, this kind of person is undoubtedly very understanding of the dynamic agent of this little trick) did a couple of years, always touch unclear context, A year or two is a hurdle, why is a year or two, only the newcomer may have no feeling for this thing, not to this step, did a long time to develop the people obviously understand this principle, and do a year or two, know its but do not know its why, so a couple of years of work experience of people are very vacant.
So, here is a relatively more in-depth introduction of the JDK Dynamic agent principle. After this presentation, I understand the truth, I believe you will always remember the idea of the JDK dynamic agent. Incidentally, what Cglib does and what the JDK dynamic agent does is similar in the end, not the same way.
1, first from the source of the JDK, dynamic agent This part of the source code, Oracle version and OPENJDK source code is not quite the same, it seems that the Oracle version of the core that something is not open source, F3 in I can not find it anyway, I am too lazy to find, but the principle is consistent, Here is the choice of openjdk.
We review the JDK Dynamic agent, first of all the macro principles, I believe all understand that the use of the JDK dynamic agent is most common, at least for me is the spring AOP part, and is the AOP part of the declarative transaction part.
A, define an interface car:
 Public Interface Car {    void Drive (String drivername, String carname);}
View Code
b, define an implementation class for the interface car Audi:
 Public class Implements Car {    @Override    publicvoid Drive (String drivername, String carname) {        System.err.println ("Audi is driving ... "+" drivername: "+ drivername +", carname "+ carname);}    }
View Code
C, define a dynamic call to the controller Carhandler:
 Public classCarhandlerImplementsInvocationhandler {Privatecar Car;  PublicCarhandler (car car) { This. Car =car; } @Override PublicObject Invoke (Object proxy, Method method, object[] args)throwsthrowable {System.err.println ("Before");        Method.invoke (car, args); System.err.println ("After"); return NULL; }}View Code
D, test class Proxytest:
 Public class proxytest {        @Test    publicvoidthrows  Exception {        = (Car) Proxy.newproxyinstance (Car.  Classnew class<?>[] {Car.  Classnew Carhandler (new  Audi ()));        Audi.drive ("name1", "Audi");     }
View Code
E, output results:
Beforeaudi is driving ... drivername:name1, carnameaudiafter
View Code
Above this paragraph, I believe we all understand, also understand the principle, this is so-called know it, but not necessarily all can know its why. The next explanation is "know why."
Enter the Newproxyinstance method of the proxy class:
     Public StaticObject newproxyinstance (ClassLoader loader, Class<?>[] interfaces, Invocationhandler h)throwsIllegalArgumentException {if(H = =NULL) {            Throw NewNullPointerException (); }        /** Look up or generate the designated proxy class. */Class<?> cl =Getproxyclass (loader, interfaces); /** Invoke Its constructor with the designated invocation handler. */        Try{Constructor cons=Cl.getconstructor (Constructorparams); returnCons.newinstance (Newobject[] {h}); } Catch(nosuchmethodexception e) {Throw NewInternalerror (e.tostring ()); } Catch(illegalaccessexception e) {Throw NewInternalerror (e.tostring ()); } Catch(instantiationexception e) {Throw NewInternalerror (e.tostring ()); } Catch(InvocationTargetException e) {Throw NewInternalerror (e.tostring ()); }    }View Code
The key 3 lines:
// To create a proxy class class<?> cl = Getproxyclass (loader, interfaces); // Instantiating proxy objects Constructor cons = Cl.getconstructor (constructorparams);
View Code
Returns an instantiated object for the proxy class. The next call is clear.
So, the key to the core of the JDK dynamic agent is this approach:
class<?> cl = getproxyclass (loader, interfaces);
Into this method, this method is very long, many of the front is foreshadowing, at the end of the method called a method:
byte [] Proxyclassfile = Proxygenerator.generateproxyclass (                    proxyname, interfaces);
This method is the method that produces the proxy object. We do not look at the front and back, only focus on this method, we write the method ourselves:
 Public class proxytest {        @SuppressWarnings ("resource")    @Test    publicvoid  Throws  Exception {        bytenew class<?>[] {Car.  Class});         New FileOutputStream (new File ("D:/audiimpl.class")). Write (BS);}    }
So, we see a file called Audiimpl.class in the D-disk, the file is anti-compilation, get the following class:
 Public Final classAudiimplextendsProxyImplementsCar {Private Static Final LongSerialversionuid = 5351158173626517207L; Private StaticMethod M1; Private StaticMethod m3; Private StaticMethod M0; Private StaticMethod m2;  PublicAudiimpl (Invocationhandler paraminvocationhandler) {Super(Paraminvocationhandler); }     Public Final Booleanequals (Object paramobject) {Try {            return((Boolean) This. H.invoke ( This, M1,Newobject[] {paramobject}).        Booleanvalue (); } Catch(Error |runtimeexception Localerror) {            ThrowLocalerror; } Catch(Throwable localthrowable) {Throw Newundeclaredthrowableexception (localthrowable); }    }     Public Final voidDrive (String paramString1, String paramString2) {Try {             This. H.invoke ( This, M3,Newobject[] {paramString1, paramString2}); return; } Catch(Error |runtimeexception Localerror) {            ThrowLocalerror; } Catch(Throwable localthrowable) {Throw Newundeclaredthrowableexception (localthrowable); }    }     Public Final inthashcode () {Try {            return(Integer) This. H.invoke ( This, M0,NULL) . Intvalue (); } Catch(Error |runtimeexception Localerror) {            ThrowLocalerror; } Catch(Throwable localthrowable) {Throw Newundeclaredthrowableexception (localthrowable); }    }     Public FinalString toString () {Try {            return(String) This. H.invoke ( This, M2,NULL); } Catch(Error |runtimeexception Localerror) {            ThrowLocalerror; } Catch(Throwable localthrowable) {Throw Newundeclaredthrowableexception (localthrowable); }    }    Static {        Try{M1= Class.forName ("Java.lang.Object"). GetMethod ("equals"),                    NewClass[] {class.forname ("Java.lang.Object") }); M3= Class.forName ("Com.mook.core.service.Car"). GetMethod ("Drive"),                    NewClass[] {class.forname ("java.lang.String"), Class.forName ("java.lang.String") }); M0= Class.forName ("Java.lang.Object"). GetMethod ("Hashcode",NewClass[0]); M2= Class.forName ("Java.lang.Object"). GetMethod ("toString"),NewClass[0]); } Catch(nosuchmethodexception localnosuchmethodexception) {Throw NewNosuchmethoderror (Localnosuchmethodexception.getmessage ()); } Catch(ClassNotFoundException localclassnotfoundexception) {Throw NewNoclassdeffounderror (Localclassnotfoundexception.getmessage ()); }    }}
At this point, all the secrets of the JDK dynamic agent are exposed to you, and when we call the drive method, we actually pass the method name to the controller and execute the controller logic. This realizes the dynamic proxy. Spring AOP has two ways to implement dynamic Proxy, if based on interface programming, the default is the JDK dynamic agent, otherwise is the Cglib way, in addition to spring configuration file can also be set to use Cglib to do dynamic agent, on the performance of the two, the Internet is also divergent opinions, However, my personal opinion, performance is not a problem, it is not necessary to struggle with this performance problem.
In fact, if you understand this, when you go to read MyBatis source code is very helpful, mybatis interface way to do method query to make full use of the JDK dynamic agent here. Otherwise if you do not understand the principle, see MyBatis Source of the interface mode is very laborious, of course, this is just mybatis use dynamic agent of the iceberg, to fully understand Mybaits source code There are many other difficulties, such as MyBatis is to configure SQL statements with XML files.
"Original" JDK dynamic agent, this time, forever unforgettable.