First, we understand the difference between dynamic agent and static agent.
Static Proxy: ① holds a reference to the proxy class ② the proxy class is loaded into memory at first (very important)
Dynamic Proxy: The proxy class in the dynamic proxy in the JDK is dynamically generated. And the generated dynamic proxy class is $proxy0
Static proxy instance 1, create an interface:
Package Proxy;public interface People {public void Zhaoduixiang () throws Throwable;}
2, create an implementation class, Zhang San, Zhang San can eat, Zhang San can find the object
Package Proxy;public class Zhangsan implements people {public void Zhaoduixiang () throws Throwable{system.out.println ("I As long as the Beautiful ");}}
3, create a implementation parent class, the parent class holds the Zhang San reference
Package Proxy;public class Hisdady implements people { Zhangsan Zs; Public Hisdady (Zhangsan zs) { This.zs=zs }public void Zhaoduixiang () throws throwable{ before () Zs.zhaoduixiang (); Afger ()} public void Afger () throws Throwable{system.out.println ("Better Family");} public void before () throws Throwable{system.out.println ("to have a degree");} }
Dynamic Agent:
1. Create a declaration class Proxyhandler
Package Proxy;import Java.awt.event.invocationevent;import Java.lang.reflect.invocationhandler;import Java.lang.reflect.method;public class Proxyhandler implements Invocationhandler{people Peaple=null;public Proxyhandler (People people) {this.peaple=people;} public void before () throws Throwable{system.out.println ("wash your hands before eating");} public void After () throws Throwable{system.out.println ("to wash dishes after eating");} @Overridepublic object Invoke (Object proxy, Method method, object[] args) throws Throwable {before (); Method.invoke ( Peaple,null); after (); return null;}}
2. Create a test class.
Package Proxy;import Java.io.filenotfoundexception;import Java.io.fileoutputstream;import java.io.IOException; Import Java.lang.reflect.proxy;import Sun.misc.proxygenerator;public class Test {public static void main (string[] args) Throws Throwable{system.out.println ("dynamic agent written by JDK"); People people= (People) Proxy.newproxyinstance (People.class.getClassLoader (), New Class[]{people.class}, new Proxyhandler (New Zhangsan ()));p eople.eat ();} public void Sleep () throws Throwable{system.out.println ("sleeping"); public void Sport () throws Throwable{system.out.println ("Sleeping");}}
Execution Result:
Printing, then people must have executed the Invoke method in Proxyhandler, and performed before () to execute Method.invoke (peaple,null) First, and finally execute after ();
So the question is, why did you do it? We clearly call the People.eat () method AH.
Parsing steps: We print the name of the People object at this point and see what the interface corresponds to:
People.eat () in Test, followed by:
System.out.println (People.getclass (). GetName ());
The result is: Proxy. $Proxy 0, what the hell is this, originally, the People object holds a class named $Proxy 0 object, we call the $proxy0 eat () method,
So we'd better look at the source code of $PROXY0:
How to read $proxy0 code (since $PROXY0JDK is automatically deleted, so we will write it to a corresponding file, the code is as follows):
package Proxy;import Java.io.filenotfoundexception;import Java.io.fileoutputstream;import Java.io.ioexception;import Java.lang.reflect.proxy;import Sun.misc.ProxyGenerator ;p Ublic class Test {public static void main (string[] args) throws throwable{system.out.println ("dynamic agent written by JDK"); People people= (People) Proxy.newproxyinstance (People.class.getClassLoader (), New Class[]{people.class}, new Proxyhandler (New Zhangsan ()));p eople.eat (); System.out.println (People.getclass (). GetName ()); Creatproxyclassfile (); public static void Creatproxyclassfile () {byte[] Data=proxygenerator.generateproxyclass ("$Proxy 0", New class[]{ People.class}); try {fileoutputstream out= new FileOutputStream ("$Proxy 0.class"); Out.write (data); Out.close ();} catch (FileNotFoundException e) {E.printstacktrace ();} catch (IOException e) {e.printstacktrace ();}} public void Sleep () throws Throwable{system.out.println ("sleeping"); public void Sport () throws Throwable{system.out.println ("Sleeping");}}
Open the corresponding project workspace and you will find a corresponding $proxy0 file;
So what's so mysterious, that when we call the $proxy0.eat () method, we call the Invoke () method.
We look at the source code of the Proxy0 class, please open the proxy0.class with the anti-compilation software:
Import Java.lang.reflect.invocationhandler;import Java.lang.reflect.method;import Java.lang.reflect.proxy;import Java.lang.reflect.undeclaredthrowableexception;import Proxy. People;public Final class $Proxy 0 extends Proxy implements people{private static Method M1; private static Method m3; private static Method M0; private static Method m2; Public $Proxy 0 (Invocationhandler Paraminvocationhandler) throws {super (Paraminvocationhandler); The public final Boolean equals (Object Paramobject) throws {try {return (Boolean) This.h.invoke (this, M1, New object[] {paramobject}). Booleanvalue (); } catch (error| RuntimeException localerror) {throw localerror; } catch (Throwable localthrowable) {throw new undeclaredthrowableexception (localthrowable); }} public final void Eat () throws Throwable {This.h.invoke (this, M3, null); The Public final int hashcode () throws {try {return ((Integer) This.h.invoke (This, M0, NULL)). Intvalue (); } catch (error| RuntimeException localerror) {throw localerror; } catch (Throwable localthrowable) {throw new undeclaredthrowableexception (localthrowable); }} public final String toString () throws {try {return (String) This.h.invoke (this, M2, null); } catch (error| RuntimeException localerror) {throw localerror; } catch (Throwable localthrowable) {throw new undeclaredthrowableexception (localthrowable); }} static {try {m1 = Class.forName ("Java.lang.Object"). GetMethod ("equals", new class[] {class.forname ("J Ava.lang.Object ")}); M3 = Class.forName ("Proxy. People "). GetMethod (" Eat ", new Class[0]); M0 = Class.forName ("Java.lang.Object"). GetMethod ("Hashcode", new Class[0]); M2 = Class.forName ("Java.lang.Object"). GetMethod ("ToString", new Class[0]); Return } catch (Nosuchmethodexception localnosuchmethodexception) {throw new NosuchmethOderror (Localnosuchmethodexception.getmessage ()); } catch (ClassNotFoundException localclassnotfoundexception) {throw new Noclassdeffounderror (Localclassnotfoun Dexception.getmessage ()); } }}
Note Some of these methods and properties, such as public final void eat () throws Throwable {This.h.invoke (this, M3, null);} , where the Eat () method of the object is called the Invoke method, what does H mean,
Because proxy0:public final class $Proxy 0 extends proxy, look at the discovery in Proxy: protected Invocationhandler H;, so H is an incoming Invocationh The Andler object, which is called the Invoke method of the Invocationhandler. So we can see why the results are printed in the console.
Pure handwritten dynamic agent, not using any JDK:
1, create a Myinvocationhandler interface, simulate Invocationhandler
Package Proxy;import Java.lang.reflect.method;public Interface Myinvocationhandler {public object Invoke (object proxy, Method Method,object args) throws Throwable;}
2, the implementation of the interface Myproxyhandler, Analog Proxyhandler, and the original dynamic agent completely a kind, just changed the code form
Package Proxy;import Java.lang.reflect.method;public class Myproxyhandler implements Myinvocationhandler {People Peaple=null;public Myproxyhandler (People people) {this.peaple=people;} public object invoke (object proxy, method method, Object args) throws Throwable {before (); Method.invoke (Peaple,null); After (); return null;} public void before () {System.out.println ("wash your hands before eating");} public void After () {System.out.println ("wash dishes after Dinner");}}
3, a new proxy class, myproxy, used to simulate proxy
Package Proxy;import Java.io.file;import Java.io.filewriter;import java.io.ioexception;import Java.lang.reflect.constructor;import Java.lang.reflect.invocationtargetexception;import Java.lang.reflect.Method ; Import Javax.tools.javacompiler;import Javax.tools.javacompiler.compilationtask;import Javax.tools.standardjavafilemanager;import Javax.tools.toolprovider;import Org.omg.corba.intf_repos;public Class myproxy {static String rt= "\r\t";p ublic static Object createproxyinstance (ClassLoader loader,class intf, Myinvocationhandler handler) {try {method[] methods=intf.getmethods ();//1 creates a Java file with a stream, String proxyclass= "package Proxy; " +rt+ "Import Java.lang.reflect.Method;" +rt+ "public class $Proxy 0 implements" +intf.getname () + "{" +rt+ "Myinvocationhandler H;" +rt+ "public $Proxy 0 (Myinvocationhandler h)" + "{" +rt+ "this.h= H;" +rt+ "}" +getmethodstring (methods,intf) +rt+ "}";//2 the class generation file, String filename= "d:/workspace/proxy/src/proxy/$ Proxy0.java "; File F=new file (filename); FileWriter fw=new FileWriter (f); Fw.writE (Proxyclass); Fw.flush (); Fw.close ();//3 compiling Java Files Javacompiler compiler=toolprovider.getsystemjavacompiler (); Standardjavafilemanager Filemgr=compiler.getstandardfilemanager (null, NULL, NULL); Iterable units= Filemgr.getjavafileobjects (filename); Compilationtask t=compiler.gettask (NULL, filemgr, NULL, NULL, NULL, units); T.call (); Filemgr.close ();// Load class into memory to Myclassloader loader1=new myclassloader ("d:/workspace/proxy/src/proxy/"); Class proxy0class=loader1.findclass ("$Proxy 0"); Constructor M=proxy0class.getconstructor (myinvocationhandler.class); Object o=m.newinstance (handler); return o;} catch (IOException e) {e.printstacktrace ();} catch (ClassNotFoundException e) {e.printstacktrace ();} catch ( Nosuchmethodexception e) {//Todo auto-generated catch Blocke.printstacktrace ();} catch (SecurityException e) {//Todo Aut O-generated catch Blocke.printstacktrace ();} catch (Instantiationexception e) {//TODO auto-generated catch Blocke.printstacktrace ();} catch (Illegalaccessexception e) {//TODO Auto-geNerated catch Blocke.printstacktrace ();} catch (IllegalArgumentException e) {//TODO auto-generated catch Blocke.printstacktrace ();} catch ( InvocationTargetException e) {//TODO auto-generated catch Blocke.printstacktrace ();} return null;} public static String getmethodstring (method[] methods,class intf) {String proxyme= "", for (Method method:methods) { proxyme+= "public void" +method.getname () + "() throws Throwable {" +rt+ "method md=" +intf.getname () + ". Class.getmethod (\" "+method.getname () +" \ ", New class[]{});" +rt+ "This.h.invoke (this,md,null);" +rt+ "}" +RT;} return proxyme;}}
4, create a test:
Package Proxy;import Java.io.filenotfoundexception;import Java.io.fileoutputstream;import java.io.IOException; Import Java.lang.reflect.proxy;import Sun.misc.proxygenerator;public class Test {public static void main (string[] args) Throws Throwable{system.out.println ("dynamic agent written by JDK"); People people= (People) Proxy.newproxyinstance (People.class.getClassLoader (), New Class[]{people.class}, new Proxyhandler (New Zhangsan ()));p eople.eat ();/*people people1= (People) myproxy.createproxyinstance ( People.class.getClassLoader (), People.class, New Myproxyhandler (New Zhangsan ())); System.out.println (People1.getclass (). GetName ()); System.out.println ("Self-written dynamic agent");p eople1.eat (); */system.out.println (People.getclass (). GetName ()); Creatproxyclassfile ();} public static void Creatproxyclassfile () {byte[] Data=proxygenerator.generateproxyclass ("$Proxy 0", New class[]{ People.class}); try {fileoutputstream out= new FileOutputStream ("$Proxy 0.class"); Out.write (data); Out.close ();} catch (FileNotFoundException e) {E.printstacktrace();} catch (IOException e) {e.printstacktrace ();}}}
Results:
This is my exercise after watching the free teaching course of the brain college, I am very grateful to Jack, the teacher is very good, I learned a lot.
SPRINGMVC Dynamic agent JDK implementation and simulation JDK pure handwriting implementation.