Spring的开发方式之一就是面向切面编程即AOP,AOP的核心构造是切面,它将那些影响多个类的行为封装到可重用的模块中。而AOP的原理就是java的动态代理机制。
本篇主要通过自定义一个Proxy类,来更深刻的理解动态代理的机制和原理。
每一个动态代理类都必须要实现InvocationHandler这个接口,并且每个代理类的实例都关联到了一个handler,当我们通过代理对象调用一个方法的时候,这个方法的调用就会被转发为由InvocationHandler这个接口的 invoke 方法来进行调用。我们来看看InvocationHandler这个接口的唯一一个方法 invoke 方法:
public interface SelfInvocationHandler { /** * * @param proxy 指代我们所代理的那个真实对象 * @param method 指代的是我们所要调用真实对象的某个方法的Method对象 * @param args 指代的是调用真实对象某个方法时接受的参数 * @return * @throws Throwable */ public Object invoke(Object proxy, Method method,Object[] args) throws Throwable ; }
Proxy这个类的作用就是用来动态创建一个代理对象的类,它提供了许多的方法,但是我们用的最多的就是 newProxyInstance 这个方法:
import javax.tools.JavaCompiler; import javax.tools.StandardJavaFileManager; import javax.tools.ToolProvider; 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; /** * 自定义代理类 */ public class SelfProxy { private static String ln = " "; /** * * @param interfaces * @return */ private static String generateStr(Class<?> interfaces) { StringBuffer src = new StringBuffer(); src.append("package com.BXD._08Reflect.self;" + ln); src.append("import java.lang.reflect.Method;" + ln); src.append("public class $Proxy0 implements " + interfaces.getName() + "{" + ln); src.append("SelfInvocationHandler h;" + ln); src.append("public $Proxy0(SelfInvocationHandler h){" + ln); src.append("this.h=h;" + ln); src.append("}" + ln); for (Method m : interfaces.getMethods() ) { src.append("public " + m.getReturnType().getName() + " " + m.getName() + "(){" + ln); src.append("try{"); src.append("Method m=" + interfaces.getName() + ".class.getMethod("" + m.getName() + "", new Class[]{});" + ln); src.append("this.h.invoke(this,m,null);" + ln); src.append("}" + ln); src.append("catch(Throwable throwable){" + ln); src.append("throwable.printStackTrace();" + ln); src.append("}"); src.append("}" + ln); } src.append("}"); return src.toString(); } /** * Proxy.newProxyInstance 创建的代理对象是在jvm运行时动态生成的一个对象 * @param loader 一个ClassLoader对象,定义了由哪个ClassLoader对象来对生成的代理对象进行加载 * @param interfaces 一个Interface对象的数组,表示的是我将要给我需要代理的对象提供一组什么接口,如果我提供了一组接口给它,那么这个代理对象就宣称实现了该接口(多态),这样我就能调用这组接口中的方法了 * @param h 一个InvocationHandler对象,表示的是当我这个动态代理对象在调用方法的时候,会关联到哪一个InvocationHandler对象上 * @return * @throws IOException * @throws ClassNotFoundException * @throws NoSuchMethodException * @throws IllegalAccessException * @throws InvocationTargetException * @throws InstantiationException */ public static Object newProxyInstance(SelfClassLoad loader, Class<?>[] interfaces, SelfInvocationHandler h) throws IOException, ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException { //1.生成源代码 String proxySrc = generateStr(interfaces[0]); //2.将生成的源代码输出到磁盘,保存为,java文件 String filePath = SelfProxy.class.getResource("").getPath(); File javaFile = new File(filePath + "$Proxy0.java"); FileWriter fw = new FileWriter(javaFile); fw.write(proxySrc); fw.flush(); fw.close(); //3.编译源代码,并且生成.class文件 JavaCompiler compiler= ToolProvider.getSystemJavaCompiler(); StandardJavaFileManager manager=compiler.getStandardFileManager(null,null,null); Iterable iterable=manager.getJavaFileObjects(javaFile); JavaCompiler.CompilationTask task=compiler.getTask(null,manager,null,null,null,iterable); task.call(); manager.close(); //4.将class文件中的内容,动态加载到JVM中来 Class proxyClass = loader.findClass("$Proxy0"); //5.返回被代理后的代理对象 Constructor c=proxyClass.getConstructor(SelfInvocationHandler.class); javaFile.delete(); return c.newInstance(h); } }
自定义ClassLoad类,用来将动态生成的.class文件加载到JVM中
import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.IOException; /** * Created by Administrator on 2018/6/23. * ClassLoader对象,对动态生成的.class文件加载到JVM */ public class SelfClassLoad extends ClassLoader{ private File baseDir; /** * */ public SelfClassLoad() { String basePath=SelfClassLoad.class.getResource("").getPath(); this.baseDir=new File(basePath); } @Override protected Class<?> findClass(String name) { String className = SelfClassLoad.class.getPackage().getName() + "." + name; if (baseDir!=null){ File classFile=new File(baseDir,name.replace("\.","/")+".class"); if (classFile.exists()){ FileInputStream in=null; ByteArrayOutputStream out=null; try { in=new FileInputStream(classFile); out=new ByteArrayOutputStream(); byte[] buff=new byte[1024]; int len; while ((len=in.read(buff))!=-1){ out.write(buff,0,len); } return defineClass(className,out.toByteArray(),0,out.size()); }catch (Exception e){ e.printStackTrace(); }finally { if (null!=in){ try { in.close(); } catch (IOException e) { e.printStackTrace(); } } if (null!=out){ try { out.close(); } catch (IOException e) { e.printStackTrace(); } } classFile.delete(); } } } return null; } }
定义一个动态代理类了,每一个动态代理类都必须要实现 InvocationHandler 这个接口,因此我们这个动态代理类也不例外
** * Created by Administrator on 2018/6/23. * 定义一个动态代理类了,每一个动态代理类都必须要实现 InvocationHandler 这个接口 */ public class Meipo implements SelfInvocationHandler { /** * 这个就是我们要代理的真实对象 */ private Person target; public Object getInstance(Person target) throws IOException, ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException { this.target=target; Class clazz=target.getClass(); System.out.println("被代理对象的class是:"+clazz); return new SelfProxy().newProxyInstance(new SelfClassLoad(),clazz.getInterfaces(),this); } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { //在代理真实对象前我们可以添加一些自己的操作 System.out.println("我是媒婆"); System.out.println("开始相亲。。。。"); //当代理对象调用真实对象的方法时,其会自动的跳转到代理对象关联的handler对象的invoke方法来进行调用 method.invoke(this.target,args); System.out.println("结束相亲......."); return null; } }
public interface Person { //相亲 void findLove(); }
public class XiaoXingXing implements Person{ @Override public void findLove() { System.out.println("相亲要求"); System.out.println("高富帅"); System.out.println("有房车"); } }
/** * 自定义动态代理 */ public class Test { public static void main(String[] args) throws IOException, ClassNotFoundException, NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException { Person xingxign=(Person)new Meipo().getInstance(new XiaoXingXing()); System.out.println(xingxign); xingxign.findLove(); } }