源码专题之spring设计模式

jdk动态代理 jdk动态代理 代码实现 满足代理模式应用场景的三个必要条件 两个角色:执行者、被代理对象 注重过程,必须要做,被代理对象没时间做或者不想做(怕羞羞),不专业 执行者必须拿到被代理对象的个人资料(执行者持有被代理对象的引用) jdk的动态代理通过调用Proxy.newProxyInstance(ClassLoader loader,Class[] interfaces,InvocationHandler h) 方法,生成目标对象的代理类,interfaces参数为目标对象所实现的全部接口,InvocationHandler的实现类负责在调用方法前后处理自定义逻辑,下面我们以媒婆介绍对象为背景实现: 1 首先是需要找对象的人 public interface Person { void findLove(); String getSex(); String getName(); } --- public class XiaoFang implements Person{ private String sex = "女"; private String name = "小芳"; @Override public void findLove() { System.out.println("我叫" + this.name + ",性别:" + this.sex + "我找对象的要求是:"); System.out.println("高富帅"); System.out.println("有房有车的"); System.out.println("身高要求180cm以上,体重70kg"); } public String getSex() { return sex; } public void setSex(String sex) { this.sex = sex; } public String getName() { return name; } public void setName(String name) { this.name = name; } } 2 小芳不好意思找对象,就要找媒婆来搭桥 public class Meipo implements InvocationHandler { private Person target; //需要代理的目标对象 //获取被代理人的个人资料 //将目标对象传入进行代理 public Object getInstance(Person target) throws Exception{ this.target = target; Class clazz = target.getClass(); System.out.println("被代理对象的class是:"+clazz); return Proxy.newProxyInstance(clazz.getClassLoader(), clazz.getInterfaces(), this);//返回代理对象 } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("开始进行海选..."); System.out.println("------------"); //代理找对象 Object ret = method.invoke(this.target, args); System.out.println("------------"); System.out.println("如果合适的话,就准备结婚); return ret; } } 3 正式开始委托媒婆找对象 public class TestFindLove { public static void main(String[] args) { try { Person obj = (Person)new Meipo().getInstance(new XiaoFang()); System.out.println(obj.getClass()); obj.findLove(); } catch (Exception e) { e.printStackTrace(); } } } 手写实现jdk动态代理 这里我们不用jdk提供的reflect api,自己手写实现jdk动态代理,来进一步看一下动态代理的内部实现。 1 需要找对象的人,参照上面的person接口及实现 2 媒婆需要获取被代理人的个人信息,并生成一个替代品(代理对象) public class MyPorxy { private static String ln = "\r\n"; public static Object newProxyInstance(MyClassLoader classLoader, Class[] interfaces, MyInvocationHandler h){ try{ //1、生成源代码 String proxySrc = generateSrc(interfaces[0]); //2、将生成的源代码输出到磁盘,保存为.java文件 String filePath = MyPorxy.class.getResource("").getPath(); File f = new File(filePath + "$Proxy0.java"); FileWriter fw = new FileWriter(f); fw.write(proxySrc); fw.flush(); fw.close(); //3、编译源代码,并且生成.class文件 JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); StandardJavaFileManager manager = compiler.getStandardFileManager(null, null, null); Iterable iterable = manager.getJavaFileObjects(f); CompilationTask task = compiler.getTask(null, manager, null, null, null, iterable); task.call(); manager.close(); //4.将class文件中的内容,动态加载到JVM中来 //5.返回被代理后的代理对象 Class proxyClass = classLoader.findClass("$Proxy0"); Constructor c = proxyClass.getConstructor(MyInvocationHandler.class); f.delete(); return c.newInstance(h); }catch (Exception e) { e.printStackTrace(); } return null; } private static String generateSrc(Class interfaces){ StringBuffer src = new StringBuffer(); src.append("package com.lh.reflect;" + ln); src.append("import java.lang.reflect.Method;" + ln); src.append("public class $Proxy0 implements " + interfaces.getName() + "{" + ln); src.append("MyInvocationHandler h;" + ln); src.append("public $Proxy0(MyInvocationHandler 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{" + ln); src.append("Method m = " + interfaces.getName() + ".class.getMethod(\"" +m.getName()+"\",new Class[]{});" + ln); src.append("this.h.invoke(this,m,null);" + ln); src.append("}catch(Throwable e){e.printStackTrace();}" + ln); src.append("}" + ln); } src.append("}"); return src.toString(); } } 3 MyClassLoader代码: //代码生成、编译、重新动态load到JVM public class MyClassLoader extends ClassLoader{ private File baseDir; public MyClassLoader(){ String basePath = MyClassLoader.class.getResource("").getPath(); this.baseDir = new java.io.File(basePath); } @Override protected Class findClass(String name) throws ClassNotFoundException { String className = MyClassLoader.class.getPackage().getName() + "." + name; if(baseDir != null){ File classFile = new File(baseDir,name.replaceAll("\\.", "/") + ".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; } } 4 接下来媒婆介绍对象的环节就水到渠成了 public interface MyInvocationHandler { public Object invoke(Object proxy, Method method, Object[] args) throws Throwable; } --- public class MyMeipo implements MyInvocationHandler { private Person target; //获取被代理人的个人资料 public Object getInstance(Person target) throws Exception{ this.target = target; Class clazz = target.getClass(); System.out.println("被代理对象的class是:"+clazz); return MyPorxy.newProxyInstance(new MyClassLoader(), clazz.getInterfaces(), this); } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("开始进行海选..."); System.out.println("------------"); Object ret = method.invoke(this.target, args); System.out.println("------------"); System.out.println("如果合适的话,就准备结婚"); return ret; } } 总结 jdk动态代理原理: 拿到被代理对象的引用,然后获取它的接口 JDK代理重新生成一个类,同时实现我们给的代理对象所实现的接口 把被代理对象的引用也拿到了 重新动态生成一个class字节码 然后编译https://www.cnblogs.com/winner2016/p/9868533.html
50000+
5万行代码练就真实本领
17年
创办于2008年老牌培训机构
1000+
合作企业
98%
就业率

联系我们

电话咨询

0532-85025005

扫码添加微信