代理模式详解

特点:

  • 1、 执行者、 被代理人
  • 2、 对于被代理人来说, 这件事情是一定要做的, 但是我自己又不想做或者没有时间做, 找代理。
  • 3、 需要获取到被代理的人个人资料。
  • 4、关心过程

穷举法:

  • 租房中介: 中介和你
  • 火车票黄牛: 黄牛和你
  • 媒人: 媒婆和你
  • 明星经纪人: 经纪人和明星 刘德华要开演唱会(长沙) 、 准备工作和善后工作

总结:

  • 做了一件什么事情呢? 字节码重组
  • 可以做一件什么事情? 可以在每一个方法调用之前加一些代码, 在方法调用之后再加一些代码

代理模式在Spring中的使用
可以做一件什么事情?
在调用方法前和方法后加入一些处理逻辑

AOP中使用场景

  • 事务代理(声明式事务, 哪个方法需要加事务, 哪个方法不需要加事务)
  • 日志监听

假如我们定义了一个service 方法

  • 开启一个事务(open) 代理来做
  • 事务的执行 执行我们的service方法
  • 监听到是否有异常, 可能需要根据异常的类型来决定这个事务是否要回滚还是继续提交 代理来做
  • (commit/rollback) 代理来做
  • 事务要关闭(close) 代理来做

代理模式的三种玩法

  • jdk代理模式
  • cglib代理模式实现
  • 手写一个代理模式

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();
}

定义一个被代理人


/**** @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;}
}

定义一个代理:


/**** @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);}@Overrideprotected 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();}//将classhreturn 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();}
}

设计模式之-代理模式相关推荐

  1. 【设计模式】代理模式 ( 动态代理 | 模拟 Java 虚拟机生成对应的 代理对象 类 )

    文章目录 前言 一.模拟 JVM 生成对应的 代理对象 二.模拟 JVM 生成对应的 代理对象 完整流程展示 1.目标对象接口 2.被代理对象 3.调用处理程序 4.模拟 JVM 生成的代理对象类 5 ...

  2. C++设计模式之代理模式

    这篇文章主要介绍了C++设计模式之代理模式,本文讲解了什么是代理模式.代理模式的使用场合.代理模式的实现代码等内容,需要的朋友可以参考下 前言 青春总是那样,逝去了才开始回味:大学生活也是在不经意间就 ...

  3. python中代理模式分为几种_Python设计模式之代理模式实例详解

    本文实例讲述了Python设计模式之代理模式.分享给大家供大家参考,具体如下: 代理模式(Proxy Pattern):为其他对象提供一种代理以控制对这个对象的访问 #!/usr/bin/env py ...

  4. 设计模式笔记——代理模式

    设计模式笔记--代理模式 代理模式介绍 代理模式通常是介于请求方和提供方的一个中介系统,请求方是发送请求的一方,提供方是根据请求提供相应资源的一方 Web中的代理服务器就是一个例子,客户端向代理服务器 ...

  5. 「设计模式(五) - 代理模式」

    「设计模式(五) - 代理模式」 一.处处可见的"代理" "代理"在平常生活司空见惯,点外卖,租房子找中介,买飞机票等等.基本上用手机就能完成,也就是不直接接触 ...

  6. Javascript 设计模式之代理模式【讲师辅导】-曾亮-专题视频课程

    Javascript 设计模式之代理模式[讲师辅导]-969人已学习 课程介绍         随着 javascript ES6/7 的发布,很多老版本的设计模式的实现,今天来看是错误的,将被彻底. ...

  7. 设计模式之一代理模式

    代理模式(代理设计模式) 代理模式的定义与特点 代理模式的结构与实现 代理模式(代理设计模式) 在有些情况下,一个客户不能或者不想直接访问另一个对象,这时需要找一个中介帮忙完成某项任务,这个中介就是代 ...

  8. 23种设计模式7_代理模式之一静态代理

    23种设计模式7_代理模式之一静态代理 1 基本介绍 代理模式:为其他对象提供一种代理以控制对这个对象的访问 代理模式也叫委托模式,它是一项基本设计技巧.许多其他的模式,如状态模式.策略模式.访问者模 ...

  9. Java中的设计模式:“代理模式”的理解

    代理模式定义: 为其他对象提供一种代理以控制对这个对象的访问.在面向对象中,有时候直接访问一些对象比较麻烦,所以代理模式就是在这个对象上加上一个访问该对象的访问层.类似于很多明星的事务实际都是交给经纪 ...

  10. 三国杀与设计模式之代理模式(Proxy)

    本人原博地址:http://blog.saymagic.cn/blog.php?id=17 三国杀案例:在五人局中,作为反贼的黄月英借黄忠的刀杀作为忠臣的夏侯惇,从这句话中我们可以总结出一个成语对不对 ...

最新文章

  1. 事件监听器 java_Java实现一个简单的事件监听器
  2. linux学习:进程间通信—管道
  3. VMware Network Adapter VMnet1和VMnet8 未识别的网络的解决方法
  4. boost::mpl模块实现front相关的测试程序
  5. 32位hex转浮点 python_python——int()、hex()、oct()、bin()、float()数值类型转换函数
  6. TiDB备份恢复方式你知多少?
  7. RenderMan:渲染技术
  8. [POJ 2891] Strange Way to Express Integers
  9. solr6.6 导入索引数据
  10. 为Android Studio 项目手动下载gradle
  11. 微信小程序图片宽高自适应
  12. Qt echarts 教程(3):qml echarts 的使用方法
  13. FlyAI小课堂:Fbank和MFCC介绍-理论和代码
  14. simulink 菜单栏 不见了
  15. 服务器监控系统图解,[图解]Attribute实现服务器监控5大步骤
  16. 英语学习口诀大全be 的用法口诀
  17. 炫我科技渲染集群管理软件
  18. 百度搜索引擎结果网址参数键盘重复速度(rsv_sug3)
  19. python对文本文件的读写
  20. 两个关于Tomcat利用的好问题

热门文章

  1. C语言判断输入的是否为数字
  2. MP4视频文件过大压缩的技巧是什么?简单步骤讲解
  3. checkpoint = torch.load(args.state_dict) ->RuntimeError: CUDA error: out of memory
  4. laravel进阶学习之laravel生命周期
  5. 祖母与猫 - 推荐图片组
  6. 人脸定位原来这么简单,小白也能上手人脸识别——人脸识别概述
  7. zimbra更换SSL证书流程
  8. STSW-LINK00x下载集合,百度云连接
  9. 录音系列:录音文件为啥是.wav格式?
  10. Vue-router中对path的误解和说明-path的正确理解。