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=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=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老师,老师讲的很好,我学了很多。

时间: 2024-10-14 00:17:33

springmvc 动态代理 JDK实现与模拟JDK纯手写实现。的相关文章

纯手写SpringBoot框架之注解方式启动SpringMVC容器

使用Java语言创建Tomcat容器,并且通过Tomcat执行Servlet,接下来,将会使用Java语言在SpringBoot创建内置Tomcat,使用注解方式启动SpringMVC容器. 代码实现.1.pom.xml文件,需要依赖的jar包. <dependencies> <!--Java语言操作Tomcat--> <dependency> <groupId>org.apache.tomcat.embed</groupId> <arti

Java动态代理机制详解(JDK 和CGLIB,Javassist,ASM)

作者:亦山 推荐:hh375的图书馆 class文件简介及加载 Java编译器编译好Java文件之后,产生.class 文件在磁盘中.这种class文件是二进制文件,内容是只有JVM虚拟机能够识别的机器码.JVM虚拟机读取字节码文件,取出二进制数据,加载到内存中,解析.class 文件内的信息,生成对应的 Class对象: class字节码文件是根据JVM虚拟机规范中规定的字节码组织规则生成的.具体class文件是怎样组织类信息的,可以参考 此博文:深入理解Java Class文件格式系列.或者

Java 动态代理机制详解(JDK 和CGLIB,Javassist,ASM)

class文件简介及加载 Java编译器编译好Java文件之后,产生.class 文件在磁盘中.这种class文件是二进制文件,内容是只有JVM虚拟机能够识别的机器码.JVM虚拟机读取字节码文件,取出二进制数据,加载到内存中,解析.class 文件内的信息,生成对应的 Class对象: class字节码文件是根据JVM虚拟机规范中规定的字节码组织规则生成的.具体class文件是怎样组织类信息的,可以参考 此博文:深入理解Java Class文件格式系列.或者是Java虚拟机规范. 下面通过一段代

java动态代理【二】:JDK动态代理的内部原理

上一章我们简单的讲解了什么是动态代理和如何使用动态代理. 这章讲解一下jdk的动态代理的内部实现: 首先查看测试代码: //创建一个静态方法,生成代理类, public static Object newProxyInstance(Object speak){ System.out.println(JDKDynamicProxy.class.getClassLoader().toString()); return Proxy.newProxyInstance(JDKDynamicProxy.cl

纯手写SpringMVC架构,用注解实现springmvc过程(动脑学院Jack老师课后自己练习的体会)

1.第一步,首先搭建如下架构,其中,annotation中放置自己编写的注解,主要包括service controller qualifier RequestMapping 第二步:完成对应的annotation: package com.cn.annotation; import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Retent

简单实现动态代理(Proxy)

最近学习了Jdk的动态代理,然后自己也简单的手写了一个. 思路: 1.根据代理的接口,生成对应的Java代码文件 2.将生成的Java文件编译成class文件 3.利用URLClassLoader加载class到Jvm中,利用反射在new出这个对象. 代理业务接口 package com.michael.pl; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; public i

【设计模式】动态代理 &amp;&amp; 模拟JDK动态代理

真正理解动态代理需要明白回答以下问题: 什么叫动态代理?怎么产生? 动态代理的作用?可配置的事务,权限控制,日志等等....只有你想不到,没有动态代理做不到. 下面来回答以上3个问题: 先说下静态代理: 方法:创建代理类,代理类包含被代理对象的方法并在被代理方法的前后加添加的方法. 创建代理类可以用继承接口或者聚合(implements)被代理对象的接口来实现,然后传入被代理对象的实例.其中聚合并继承好,使用继承的时候如果代理类需要嵌套代理类或者创建不同的代理类,需要创建不同的代理类.造成类泛滥

Spring AOP详解 、 JDK动态代理、CGLib动态代理

AOP是Aspect Oriented Programing的简称,面向切面编程.AOP适合于那些具有横切逻辑的应用:如性能监测,访问控制,事务管理以及日志记录.AOP将这些分散在各个业务逻辑中的代码通过横向切割的方式抽取到一个独立的模块中. 一.AOP术语 1.连接点(Joinpoint) 程序执行的某个特定位置:如类开始初始化之前.类初始化之后.类某个方法调用前.调用后等:一个类或一段程序代码拥有一些具有边界性质的特定点,这些代码中的特定点就成为“连接点”,Spring仅支持方法的连接点,即

【转载】Spring AOP详解 、 JDK动态代理、CGLib动态代理

原文地址:https://www.cnblogs.com/kukudelaomao/p/5897893.html AOP是Aspect Oriented Programing的简称,面向切面编程.AOP适合于那些具有横切逻辑的应用:如性能监测,访问控制,事务管理以及日志记录.AOP将这些分散在各个业务逻辑中的代码通过横向切割的方式抽取到一个独立的模块中. 一.AOP术语 1.连接点(Joinpoint) 程序执行的某个特定位置:如类开始初始化之前.类初始化之后.类某个方法调用前.调用后等:一个类