代理模式详解
特点:
穷举法:
总结:
代理模式在Spring中的使用
可以做一件什么事情?
在调用方法前和方法后加入一些处理逻辑
AOP中使用场景
假如我们定义了一个service 方法
代理模式的三种玩法
jdk代理模式实现
通过接口实现代理模式,先定义一个接口:
/** * * @author DoubleChina * @date 2018/1/6 11:54 */ public interface Person { //寻找真爱、相亲 void findLove(); }
实现这个接口:
/** * * @author DoubleChina * @date 2018/1/6 11:54 */ public interface Person { //寻找真爱、相亲 void findLove(); } 定义一个被代理人 ```java /** * * @author DoubleChina * @date 2018/1/6 11:53 */ public class Jack implements Person { private String sex = "男"; private String name = "Jack"; public void findLove() { System.out.println("我叫" + this.name + ",性别是" + this.sex); System.out.println("喜欢长的漂亮的"); System.out.println("身高165的"); } 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; } } <div class="se-preview-section-delimiter"></div>
定义一个代理: <div class="se-preview-section-delimiter"></div> ```java /** * * @author DoubleChina * @date 2018/1/6 11:53 */ public class MyProxy implements InvocationHandler { private Person person; //获取被代理人的资料 public Object getInstance(Person target) throws Exception { this.person = target; Class zz = target.getClass(); return Proxy.newProxyInstance(zz.getClassLoader(), zz.getInterfaces(), this); } public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("我是媒婆:您的性别是:男"); System.out.println("开始海选"); method.invoke(this.person,args); System.out.println("如何合适的话,就准备办事"); return null; } }
测试代理
/** * * @author DoubleChina * @date 2018/1/6 11:54 */ public class TestFindLove { public static void main(String[] args) { try { Person person = (Person) new MyProxy().getInstance(new Jack()); person.findLove(); System.out.println(person.getClass()); //原理: //1.拿到被代理对象的引用,然后获取它的接口 //2.JDK代理重新生成一个类,同时实现我们给的代理对象所实现的接口 //3.把被代理对象的引用也拿到了 //4.重新动态生成了一个class字节码 //5.然后编译 byte[] data = ProxyGenerator.generateProxyClass("$Proxy0", new Class[]{person.getClass()}); FileOutputStream os = new FileOutputStream("E:/learn/$Proxy0.class"); os.write(data); os.close(); } catch (Exception e) { e.printStackTrace(); } } }
cglib代理模式实现
maven需要导入Spring的核心库
<exclusions> <exclusion> <artifactId>servlet-api</artifactId> <groupId>javax.servlet</groupId> </exclusion> </exclusions>
定义一个被代理人
/** * * @author DoubleChina * @date 2018/1/6 11:53 */ public class Python { public void learnPython() { System.out.println("看我72变"); } }
代理执行者
/** * * @author DoubleChina * @date 2018/1/6 11:52 */ public class LanguageProxy implements MethodInterceptor { public Object getInstance(Class clazz) throws Exception{ //通过反射机制给他实例化 Enhancer enhancer=new Enhancer(); //注入父类,告诉CGLib,生成的子类需要继承那个类 enhancer.setSuperclass(clazz); //添加监听 enhancer.setCallback(this); //1.生成源代码 //2.编译成.class文件 //3.加载到JVM中,返回对象 return enhancer.create(); } //也是做了字节码重组,jdk实现需要实现接口,cglib则是通过继承的方式 //对于使用api无法感知的 public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { System.out.println("-----------------学习开始-----------------"); System.out.println("我正在学习Python"); System.out.println("我正在学习大数据"); //JDK的动态代理是通过接口来强制转换的 //生成以后的代理对象是可以强制转化为我们的接口 //CGLib的动态代理是通过生成一个被代理对象的子类,然后重写了父类的方法 //生成的对象,可以强制为被代理的对象(也就是用户自己写的类) //子类引用赋值给父类 //此处的 Object o对象是CGLib帮我么new出来子类的对象 //Java OOP,在new子类的同时,实际上默认先调用了我们super()的方法 //new了父类的同时,必须向new出来父类,这也就是间接持有了我们父类的引用 //我们改变了子类对象的某些属性,是可以间接的操作父类的属性的 methodProxy.invokeSuper(o,objects); System.out.println("-----------------学习结束-----------------"); return o; } }
测试实现
/** * * @author DoubleChina * @date 2018/1/6 11:53 */ public class TestLanguage { public static void main(String[] args) { try { Python python = (Python)new LanguageProxy().getInstance(Python.class); python.learnPython(); } catch (Exception e) { e.printStackTrace(); } } }
手写一个代理模式
定义一个被代理人
/** * * @author DoubleChina * @date 2018/1/6 11:53 */ public class Jack implements Person { private String sex = "男"; private String name = "Jack"; public void findLove() { System.out.println("我叫" + this.name + ",性别是" + this.sex); System.out.println("喜欢长的漂亮的"); System.out.println("身高165的"); } 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; } }
自定义一个代理
import main.proxy.jdk.Person; import java.lang.reflect.Method; /** * * @author DoubleChina * @date 2018/1/6 11:53 */ public class ZdyMeiPo implements MyInvocationHandler { private Person person; //获取被代理人的资料 public Object getInstance(Person target) throws Exception { this.person = target; Class zz = target.getClass(); return ZdyPorxy.newProxyInstance(new ZdyClassLoader(), zz.getInterfaces(), this); } public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("我是媒婆:您的性别是:男" ); System.out.println("开始海选"); method.invoke(this.person, args); System.out.println("如何合适的话,就准备办事"); return null; } }
定义一个加载器
/** * * @author DoubleChina * @date 2018/1/6 11:53 */ public class ZdyClassLoader extends ClassLoader { private File baseDir; public ZdyClassLoader() { String basePath = ZdyClassLoader.class.getResource("").getPath(); this.baseDir = new File(basePath); } @Override protected Class<?> findClass(String name) throws ClassNotFoundException { String className = ZdyClassLoader.class.getPackage().getName() + "." + name; if (baseDir != null) { File classFile=new File(baseDir,name.replaceAll("\\.","/")+".class"); if (classFile.exists()){ FileInputStream inputStream=null; ByteArrayOutputStream outputStream=null; try { inputStream=new FileInputStream(classFile); outputStream=new ByteArrayOutputStream(); byte[] buff=new byte[1024]; int len; while ((len=inputStream.read(buff))!=-1){ outputStream.write(buff,0,len); } return defineClass(className,outputStream.toByteArray(),0,outputStream.size()); } catch (Exception e) { e.printStackTrace(); }finally { classFile.delete(); if (inputStream!=null){ try { inputStream.close(); } catch (IOException e) { e.printStackTrace(); } } if (null==outputStream){ try { outputStream.close(); } catch (IOException e) { e.printStackTrace(); } } } } } return null; } }
底层实现代理全过程实现
import javax.tools.JavaCompiler; import javax.tools.StandardJavaFileManager; import javax.tools.ToolProvider; import java.io.File; import java.io.FileWriter; import java.lang.reflect.Constructor; import java.lang.reflect.Method; /** * 生成代理对象的代码 * @author DoubleChina * @date 2018/1/6 11:53 */ public class ZdyPorxy { private final static String ln = "\n\t"; public static Object newProxyInstance(ZdyClassLoader loader, Class<?> interfaces[], MyInvocationHandler h) throws IllegalArgumentException { //1.生成源代码 String porxySrc = generateSrc(interfaces); //2.将生成的源代码输出到磁盘,保存为.java文件 String filePath = ZdyPorxy.class.getResource("").getPath(); File file = new File(filePath + "$Proxy0.java"); System.out.println(filePath + "$Proxy0.java"); try { FileWriter fileWriter = new FileWriter(file); fileWriter.write(porxySrc); fileWriter.flush(); fileWriter.close(); //3.编译源代码,生成.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(); //4.将class文件中的内容,动态加载到JVM中来 Class proClass = loader.findClass("$Proxy0"); //5.返回被代理后的对象 Constructor constructor = proClass.getConstructor(MyInvocationHandler.class); // file.delete(); return constructor.newInstance(h); } catch (Exception e) { e.printStackTrace(); } //将classh return null; } private static String generateSrc(Class<?>[] interfaces) { StringBuffer src = new StringBuffer(); src.append("package main.proxy.custom; " + ln); src.append("import java.lang.reflect.Method; " + ln); // src.append("public class $Proxy0 extend ZdyPorxy implements "); src.append("public class $Proxy0 implements " + interfaces[0].getName() + "{ " + ln); //声明变量 src.append("MyInvocationHandler h; " + ln); //写入构造方法 src.append("public $Proxy0(MyInvocationHandler h) {"); src.append("this.h=h;" + ln); src.append("}" + ln); //迭代方法 for (Method method : interfaces[0].getMethods()) { src.append("public " + method.getReturnType().getName() + " " + method.getName() + "() {" + ln); src.append("try {" + ln); src.append("Method m=" + interfaces[0].getName() + ".class.getMethod(\"" + method.getName() + "\",new Class[]{});" + ln); src.append("this.h.invoke(this,m,null);" + ln); src.append(" } catch (Throwable throwable) {" + ln); src.append(" throwable.printStackTrace();" + ln); src.append(" }" + ln); src.append("}" + ln); } src.append("}"); return src.toString(); } }
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!