动态代理:字节码重组,即在每一个方法调用前后加些代码
Inter:
package proxy.jdk; /** * */ public interface Inter { void findPerson(); }
Boss:
package proxy.jdk; /** * Boss 到inter上找Person * */ public class Boss implements Inter { @Override public void findPerson() { System.out.println("我要找java架构师"); } }
WebApp:
import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; /** * 找Person的App */ public class WebApp implements InvocationHandler { private Object target;//被代理对象的引用作为一个成员变量保存下来了 //获取被代理人的个人资料 public Object getInstance(Object target){ this.target = target; Class<?> clazz = target.getClass(); System.out.println("被代理的对象:"+clazz); return Proxy.newProxyInstance(clazz.getClassLoader(),clazz.getInterfaces(),this); } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { before(); Object o = method.invoke(this.target,args); after(); return o; } private void after() { System.out.println("---------------"); } private void before() { System.out.println("找Person,找我WebApp"); System.out.println("---------------"); } }
Test:
package proxy.jdk; import sun.misc.ProxyGenerator; import java.io.File; import java.io.FileOutputStream; import java.io.InputStream; /** * 1.拿到被代理对象的引用,然后获取它的接口 * 2.JDK代理重新生成一个类,同时实现我们给的代理对象所实现的接口 * 3.把被代理对象的引用也拿到了 * 4.重新动态生成一个class字节码 * 5.然后编译 */ public class Test { public static void main(String[] args){ try { Inter obj = (Inter) new WebApp().getInstance(new Boss()); System.out.println(obj.getClass()); obj.findPerson(); //获取字节码内容 // 使用Jad反编译
// idea安装插件 Java Bytecode Decompiler即可
// byte[] bytes = ProxyGenerator.generateProxyClass("$Proxy0", new Class[]{Inter.class}); // FileOutputStream os = new FileOutputStream("./$Proxy0.class"); // os.write(bytes); // os.close(); } catch (Exception e) { e.printStackTrace(); } } }
反编译后的代码
// // Source code recreated from a .class file by IntelliJ IDEA // (powered by Fernflower decompiler) // import com.vip.proxy.jdk.Inter; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.lang.reflect.UndeclaredThrowableException; public final class $Proxy0 extends Proxy implements Inter { private static Method m1; private static Method m2; private static Method m3; private static Method m0; public $Proxy0(InvocationHandler var1) throws { super(var1); } public final boolean equals(Object var1) throws { try { return (Boolean)super.h.invoke(this, m1, new Object[]{var1}); } catch (RuntimeException | Error var3) { throw var3; } catch (Throwable var4) { throw new UndeclaredThrowableException(var4); } } public final String toString() throws { try { return (String)super.h.invoke(this, m2, (Object[])null); } catch (RuntimeException | Error var2) { throw var2; } catch (Throwable var3) { throw new UndeclaredThrowableException(var3); } } public final void findPerson() throws { try { super.h.invoke(this, m3, (Object[])null); } catch (RuntimeException | Error var2) { throw var2; } catch (Throwable var3) { throw new UndeclaredThrowableException(var3); } } public final int hashCode() throws { try { return (Integer)super.h.invoke(this, m0, (Object[])null); } catch (RuntimeException | Error var2) { throw var2; } catch (Throwable var3) { throw new UndeclaredThrowableException(var3); } } static { try { m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object")); m2 = Class.forName("java.lang.Object").getMethod("toString"); m3 = Class.forName("com.vip.proxy.jdk.Inter").getMethod("findPerson"); m0 = Class.forName("java.lang.Object").getMethod("hashCode"); } catch (NoSuchMethodException var2) { throw new NoSuchMethodError(var2.getMessage()); } catch (ClassNotFoundException var3) { throw new NoClassDefFoundError(var3.getMessage()); } } }
发现$Proxy0 继承了 Proxy 类,同时还实现了我们的 Inter接口,而且重写了findPerson()等方法。而且在静态块中用反射查找到了目标对象的所有方法,而且保存了所 有方法的引用,在重写的方法用反射调用目标对象的方法
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
手动实现一个?
MyInvocationHandler:
package proxy.myproxy; import java.lang.reflect.Method; public interface MyInvocationHandler { public Object invoke(Object proxy, Method method, Object[] args) throws Throwable; }
MyClassLoader:
package proxy.myproxy; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.IOException; /** * 代码生成、编译、重新动态load到JVM */ public class MyClassLoader extends ClassLoader { private File baseDir; public MyClassLoader() { String path = MyClassLoader.class.getResource("").getPath(); this.baseDir = new File(path); } @Override protected Class<?> findClass(String name) throws ClassNotFoundException { String className = MyClassLoader.class.getPackage().getName() + "." + name; if (baseDir!=null){ File classFile = new File(baseDir,name+".class"); if (classFile.exists()){ FileInputStream in = null; ByteArrayOutputStream out = null; try { in = new FileInputStream(classFile); out = new ByteArrayOutputStream(); byte[] bytes = new byte[1024]; int len; while ((len=in.read(bytes))!=-1){ out.write(bytes,0,len); } return defineClass(className,out.toByteArray(),0,out.size()); }catch (Exception e){ e.printStackTrace(); }finally { classFile.delete(); if (null!=in){ try { in.close(); } catch (IOException e) { e.printStackTrace(); } } if (null!=out){ try { out.close(); } catch (IOException e) { e.printStackTrace(); } } } } } return null; } }
MyProxy:
package proxy.myproxy; import javax.tools.JavaCompiler; import javax.tools.JavaFileObject; 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.Method; /** * 生成代理对象 */ public class MyProxy { public static Object newProxyInstance(MyClassLoader loader, Class<?>[] interfaces, MyInvocationHandler h) { try { String proxySrc = generateSrc(interfaces[0]); //将生成的源代码输出到磁盘,保存为.java文件 String path = MyProxy.class.getResource("").getPath(); File file = new File(path+"$Proxy0.java"); FileWriter fw = new FileWriter(file); fw.write(proxySrc); fw.flush(); fw.close(); //编译源代码,并且生成.class文件 JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); StandardJavaFileManager manager = compiler.getStandardFileManager(null, null, null); Iterable iterable = manager.getJavaFileObjects(file); JavaCompiler.CompilationTask task = compiler.getTask(null, manager, null, null, null, iterable); task.call(); manager.close(); //将class文件中的内容,动态加载到JVM中来 Class<?> proxyClass = loader.findClass("$Proxy0"); //返回被代理后的代理对象 //1 获取构造 Constructor c = proxyClass.getConstructor(MyInvocationHandler.class); file.delete(); //2 返回实例 return c.newInstance(h); } catch (Exception e) { e.printStackTrace(); } return null; } private static String ln = " "; //生成源代码 //参考反编译代码 private static String generateSrc(Class<?> interfaces){ StringBuffer src = new StringBuffer(); String name = MyClassLoader.class.getPackage().getName(); src.append("package "+name+";"+ln); src.append("import java.lang.reflect.Method;"+ln); src.append("public class $Proxy0 implements "+interfaces.getName()); src.append("{"+ln); src.append("MyInvocationHandler invocationHandler;"+ln); src.append("public $Proxy0(MyInvocationHandler invocationHandler) {"+ln); src.append("this.invocationHandler = invocationHandler;"+ln); src.append("}"+ln); for (Method m:interfaces.getMethods()){ src.append("public "+m.getReturnType()+" "+m.getName()+"(){"+ln); src.append("try{" + ln); src.append("Method m = " + interfaces.getName() + ".class.getMethod("" +m.getName()+"",new Class[]{});" + ln); src.append("this.invocationHandler.invoke(this,m,null);" + ln); src.append("}catch(Throwable e){e.printStackTrace();}" + ln); src.append("}" + ln); } src.append("}"); return src.toString(); } }
MyWebApp:
package proxy.myproxy; import proxy.jdk.Inter; import java.lang.reflect.Method; import java.lang.reflect.Proxy; /** * */ public class MyWebApp implements MyInvocationHandler { private Inter target;//被代理对象的引用作为一个成员变量保存下来了 //获取被代理人的个人资料 public Object getInstance(Inter target)throws Exception{ this.target = target; Class clazz = target.getClass(); System.out.println("被代理的对象:"+clazz); return MyProxy.newProxyInstance(new MyClassLoader(),clazz.getInterfaces(),this); } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("找Person,找我MyWebApp"); System.out.println("---------------"); method.invoke(this.target,args); System.out.println("---------------"); return null; } }
Test:
package proxy.myproxy; import proxy.jdk.Boss; import proxy.jdk.Inter; /** * */ public class Test { public static void main(String[] args){ try { Inter obj = (Inter) new MyWebApp().getInstance(new Boss()); obj.findPerson(); } catch (Exception e) { e.printStackTrace(); } } }
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
#### JDK Proxy 采用字节重组,重新生的对象来替代原始的对象以达到动态代理 的目的。JDK Proxy 生成对象的步骤如下:
1. 拿到被代理对象的引用,并且获取到它的所有的接口,反射获取。
2. JDK Proxy 类重新生成一个新的类、同时新的类要实现被代理类所有实现的所有的接 口。
3. 动态生成 Java 代码,把新加的业务逻辑方法由一定的逻辑代码去调用(在代码中体
现)。
4. 编译新生成的 Java 代码.class。
5. 再重新加载到 JVM 中运行。