首页 > 代码库 > springmvc 动态代理 JDK实现与模拟JDK纯手写实现。

springmvc 动态代理 JDK实现与模拟JDK纯手写实现。

首先明白 动态代理和静态代理的区别;

     静态代理:①持有被代理类的引用  ② 代理类一开始就被加载到内存中了(非常重要)

            动态代理:JDK中的动态代理中的代理类是动态生成的。并且生成的动态代理类为$Proxy0

 静态代理实例1、创建一个接口:

package proxy;public interface People {	public void zhaoduixiang()throws Throwable;	}

 2、创建一个实现类,张三,张三能够吃饭,张三可以找对象

package proxy;public class ZhangSan implements People {	public void zhaoduixiang() throws Throwable{		System.out.println(" 我只要漂亮的");			}	}

 3、创建一个实现父类,父类持有张三的引用

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

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类 。

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会自动删除,所以我们要把它写入到一个对应的文件中 ,代码如下):

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=http://www.mamicode.com/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:

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

package proxy;import java.lang.reflect.Method;public interface MyInvocationHandler {	public Object invoke(Object proxy,Method method,Object args)		throws Throwable;}

 2、实现该接口MyProxyHandler,模拟ProxyHandler,和原来动态代理完全一个样,只是改了下代码形式

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

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、创建一个测试:

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=http://www.mamicode.com/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老师,老师讲的很好,我学了很多。

springmvc 动态代理 JDK实现与模拟JDK纯手写实现。