springmvc 动态代理 JDK实现与模拟JDK纯手写实现。
首先明白 动态代理和静态代理的区别;
静态代理:①持有被代理类的引用 ② 代理类一开始就被加载到内存中了(非常重要)
动态代理:JDK中的动态代理中的代理类是动态生成的。并且生成的动态代理类为$Proxy0
静态代理实例1、创建一个接口:
1 2 3 4 5 6 | package proxy; public interface People { public void zhaoduixiang() throws Throwable; } |
2、创建一个实现类,张三,张三能够吃饭,张三可以找对象
1 2 3 4 5 6 7 8 9 10 | package proxy; public class ZhangSan implements People { public void zhaoduixiang() throws Throwable{ System.out.println( " 我只要漂亮的" ); } } |
3、创建一个实现父类,父类持有张三的引用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | 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( " 家境要好" ); } public void before() throws Throwable{ System.out.println( " 要有学历" ); } } |
动态代理:
1、创建一个申明类ProxyHandler
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | 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( "吃饭之前要洗手" ); } public void after() throws Throwable{ System.out.println( "吃饭以后要洗碗" ); } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { before(); method.invoke(peaple, null ); after(); return null ; } } |
2、创建一个test类 。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | 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( "JDK写的动态代理" ); People people=(People) Proxy.newProxyInstance(People. class .getClassLoader(), new Class[]{People. class }, new ProxyHandler( new ZhangSan())); people.eat(); } public void sleep() throws Throwable{ System.out.println( "睡觉" ); } public void sport() throws Throwable{ System.out.println( "睡觉" ); } } |
执行结果:
打印如图所示,那么People一定执行了ProxyHandler 中的invoke方法,并且首先执行before() 再执行method.invoke(peaple,null);最后执行 after();
那么问题来了,为什么会这么执行了?我们明明调用的People.eat()方法啊。
解析步骤:我们打印此时的People对象的名字,看看接口对应中到底是个什么东西:
在test中的 people.eat();后面加入:
System.out.println(people.getClass().getName());
打印结果为:Proxy.$Proxy0 ,这是个什么鬼东西,原来,people对象中保存的是一个类名为 $Proxy0的对象,我们调用的是$Proxy0的eat()方法,
所以我们最好看看$Proxy0的源码:
如何读取$Proxy0的代码(由于$Proxy0JDK会自动删除,所以我们要把它写入到一个对应的文件中 ,代码如下):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 | 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( "JDK写的动态代理" ); People people=(People) Proxy.newProxyInstance(People. class .getClassLoader(), new Class[]{People. class }, new ProxyHandler( new ZhangSan())); people.eat(); System.out.println(people.getClass().getName()); creatProxyClassFile(); } public static void creatProxyClassFile(){ byte [] data=ProxyGenerator.generateProxyClass( "$Proxy0" , new Class[]{People. class }); try { FileOutputStream out= new FileOutputStream( "$Proxy0.class" ); out.write(data); out.close(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } public void sleep() throws Throwable{ System.out.println( "睡觉" ); } public void sport() throws Throwable{ System.out.println( "睡觉" ); } } |
打开对应的项目工作空间,你会发现一个对应$Proxy0文件;
那么其中有什么玄妙,导致我们调用$Proxy0.eat()方法的时候,会调用invoke()方法了
我们看看Proxy0类的源码,请用反编译软件打开Proxy0.class:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 | 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 $Proxy0 extends Proxy implements People { private static Method m1; private static Method m3; private static Method m0; private static Method m2; public $Proxy0(InvocationHandler paramInvocationHandler) throws { super (paramInvocationHandler); } 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 ); } 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( "java.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(localClassNotFoundException.getMessage()); } } } |
请注意其中的一些方法和属性,比如public final void eat() throws Throwable { this.h.invoke(this, m3, null); } ,其中 该对象的eat()方法是调用的invoke 方法,那h是什么意思,
因为Proxy0 :public final class $Proxy0 extends Proxy,在Proxy中查看 发现: protected InvocationHandler h;,所以h就是一个我们传入的InvocationHandler 对象,也就是调用的是InvocationHandler 的invoke方法。 这样我们就明白了为什么会出现console中打印的结果了吧。
纯手写动态代理,不使用任何JDK:
1、 创建一个MyInvocationHandler 接口,模拟InvocationHandler
1 2 3 4 5 6 7 8 | package proxy; import java.lang.reflect.Method; public interface MyInvocationHandler { public Object invoke(Object proxy,Method method,Object args) throws Throwable; } |
2、实现该接口MyProxyHandler,模拟ProxyHandler,和原来动态代理完全一个样,只是改了下代码形式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | 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( "吃饭之前要洗手" ); } public void after(){ System.out.println( "吃饭以后要洗碗" ); } } |
3、新建一个Proxy类,MyProxy,用来模拟Proxy
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 | 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" ; public static Object createProxyInstance(ClassLoader loader,Class intf,MyInvocationHandler handler){ try { Method[] methods=intf.getMethods(); //1用流的方式创建一个Java文件, String proxyClass= "package proxy;" +rt + "import java.lang.reflect.Method;" +rt + "public class $Proxy0 implements " +intf.getName()+ "{" +rt + "MyInvocationHandler h;" +rt + "public $Proxy0(MyInvocationHandler h)" + "{" +rt + "this.h= h;" +rt+ "}" +getMethodString(methods,intf)+rt+ "}" ; //2 把类生成文件, 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编译Java文件 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(); //把class加载到内存中去 MyClassLoader loader1= new MyClassLoader( "D:/WorkSpace/proxy/src/proxy/" ); Class proxy0Class=loader1.findClass( "$Proxy0" ); 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 block e.printStackTrace(); } catch (SecurityException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (InstantiationException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IllegalAccessException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IllegalArgumentException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (InvocationTargetException e) { // TODO Auto-generated catch block e.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、创建一个测试:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 | 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( "JDK写的动态代理" ); People people=(People) Proxy.newProxyInstance(People. class .getClassLoader(), new Class[]{People. class }, new ProxyHandler( new ZhangSan())); people.eat(); /* People people1=(People) MyProxy.createProxyInstance(People.class .getClassLoader(),People.class, new MyProxyHandler( new ZhangSan())); System.out.println(people1.getClass().getName()); System.out.println("自己写的动态代理"); people1.eat(); */ System.out.println(people.getClass().getName()); creatProxyClassFile(); } public static void creatProxyClassFile(){ byte [] data=ProxyGenerator.generateProxyClass( "$Proxy0" , new Class[]{People. class }); try { FileOutputStream out= new FileOutputStream( "$Proxy0.class" ); out.write(data); out.close(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } } |
结果:
此次是我观看动脑学院免费教学课后的练习,非常感谢Jack老师,老师讲的很好,我学了很多。
【推荐】还在用 ECharts 开发大屏?试试这款永久免费的开源 BI 工具!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步