本文共 8966 字,大约阅读时间需要 29 分钟。
Spring中的AOP底层就是基于动态代理实现的,下面介绍两种动态代理模式。
代码实现
满足代理模式应用场景的三个必要条件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到JVMpublic 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动态代理原理:在Spring AOP中,通常会用它来生成AopProxy对象。不仅如此,在Hibernate中PO(Persistant Object 持久化对象)字节码的生成工作也要靠它来完成。
代码实现:
1 被代理类
public class GaoFuShuai { public void findLove(){ System.out.println("肤白貌美大长腿"); }}
2 媒婆(生成代理类,代找对象)
public class GPMeipo implements MethodInterceptor{ //疑问? //好像并没有持有被代理对象的引用 public Object getInstance(Class clazz) throws Exception{ Enhancer enhancer = new Enhancer(); //把父类设置为谁? //这一步就是告诉cglib,生成的子类需要继承哪个类 enhancer.setSuperclass(clazz); //设置回调 enhancer.setCallback(this); //第一步、生成源代码 //第二步、编译成class文件 //第三步、加载到JVM中,并返回被代理对象 return enhancer.create(); } //同样是做了字节码重组这样一件事情 //对于使用API的用户来说,是无感知 @Override public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { System.out.println("开始进行海选..."); System.out.println("------------"); //这个obj的引用是由CGLib给我们new出来的 //cglib new出来以后的对象,是被代理对象的子类(继承了我们自己写的那个类) //OOP, 在new子类之前,实际上默认先调用了我们super()方法的, //new了子类的同时,必须先new出来父类,这就相当于是间接的持有了我们父类的引用 //子类重写了父类的所有的方法 //我们改变子类对象的某些属性,是可以间接的操作父类的属性的 proxy.invokeSuper(obj, args); System.out.println("------------"); System.out.println("如果合适的话,就准备结婚"); return null; }}
转载地址:http://rysel.baihongyu.com/