代理模式.txt 6.4 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798
  1. 代理模式
  2. 代理模式(Proxy Pattern)是Java中常用的一种设计模式。它属于【结构型】模式。
  3. 1、代理模式的核心思想:
  4. 通过一个"代理对象"来代替"真实对象",通过这种方式来控制对"真实对象"的访问。
  5. 说人话,代理模式中代理,就是代理人,中介。
  6. 代理模式就像中介、代购、经纪人。比如想租房,不需要直接找房东(真实对象),
  7. 而是找中介(代理对象)。中介会帮你联系房东,还能额外提供看房、签合同等等服务。
  8. 2、代理模式的核心特点:
  9. 1、【代理类和真实类实现相同的接口,或者继承相同的父类】,保证代理对象和真实对象都能
  10. 被统一使用,比如房东可以令你看房,中介也可以领你看房。
  11. 2、【代理类持有真实对象的引用,可以直接调用真实对象的方法】,比如:中介手里有房东的联系方式,
  12. 能够让房东最终交房。
  13. 3、【代理类可以在调用真实对象的方法前后,添加额外的操作】。比如:中介要在签合同之前核实你的身份,
  14. 签完合同要给中介费。
  15. 3、为什么需要代理模式?
  16. 代理模式的核心价值其实就是"控制访问"和"增强功能":
  17. 1、保护真实对象,比如限制只有管理员才能访问某一个敏感对象
  18. 2、增强功能:在不修改真实对象的代码的前提下,添加一些功能,日志、权限校验、缓存等等功能
  19. 3、远程访问:通过代理模式访问远端服务器里面的对象
  20. 4、代理模式的分类:
  21. 静态代理
  22. 动态代理
  23. 两种代理方式核心逻辑是一样的, 但是实现的方式和使用的场景不一样。
  24. --------------------------------------------------------------
  25. 静态代理(static proxy)
  26. 静态代理就是在编译期就已经确定了代理类的代码, 需要我们手动写代理类。
  27. 实现步骤:租房
  28. 1、定义接口(代表代理类和真实类有共同的行为)
  29. 接口,其实就是代理类和真实类的"约定",确保两个类能够被统一调用,
  30. 创建一个Rent接口,包含租房方法。
  31. 2、实现真实类---被代理的对象
  32. 就是房东,是最终提供服务的对象,需要实现Rent接口
  33. 3、实现代理类---中介
  34. |-实现Rent接口,保证行为和真实类一致。
  35. |-持有真实类的引用,可以通过构造传入。
  36. |-在调用真实类的方法的前后,添加额外的操作,比如中介的服务
  37. 静态代理的优缺点:
  38. 优点:
  39. 简单、直观、代码好理解、不需要依赖复杂的框架。
  40. 缺点:
  41. 当接口新增方法,代理类和真实类都需要修改。
  42. 有多少个真实类,就得有多少个代理类
  43. 动态代理(Dynamic Proxy)
  44. 动态代理是在程序运行时,通过反射动态生成代理类的代码,不需要我们手动编写代理类。
  45. 解决了静态代理的每个真实类都要手写一个代理类的情况,适合批量处理多个类的场景。
  46. Java中常用的动态代理有两种:
  47. JDK动态代理,基于接口的。
  48. CGLIB动态代理,基于继承的。
  49. 1、JDK动态代理是Java官方提供的,java.lang.reflect包里,要求被代理的类必须要实现接口。
  50. 以给所有的方法添加日志,作为例子:
  51. 实现步骤:
  52. 1、定义接口(比如:UserService)和真实类(实现类:UserServiceImpl)
  53. 2、实现InvocationHandler接口,里面是代理逻辑
  54. JDK动态代理需要一个"调用处理程序|调用处理器",实现InvocationHandler接口,
  55. 用来定义代理类的额外操作,比如日志。
  56. InvocationHandler接口里只有一个抽象方法:
  57. Object invoke(Object proxy, Method method, Object[] args)throws Throwable;
  58. 包含参数:
  59. proxy:动态生成的奥地利对象,一般我们是不用的
  60. method:当前调用的方法,比如addUser、deleteUser
  61. args:方法的参数列表,比如addUser的参数。
  62. 我们既然要使用JDK动态代理实现为每个方法添加日志,就要创建一个日志处理类
  63. 3、生成代理对象,并且进行测试
  64. 通过Proxy.newProxyInstance()方法动态的生成代理对象。
  65. newProxyInstance()方法需要传入3个参数:
  66. |-ClassLoader loader 真实类的类加载器 target.getClass().getClassLoader();
  67. |-Class<?>[] interfaces 真实类实现的接口 target.getClass().getInterfaces();
  68. |-InvocationHandler h 调用处理器,比如我们自己创建的日志处理器LogHandler
  69. JDK动态代理只能代理"实现了某个接口的类",如果某个类没有接口,那么就代理不了。这时候就需要CGLIB动态代理
  70. CGLIB动态代理,基于继承的。
  71. CGLIB动态代理是一个第三方库,是通过继承被代理类生成代理子类,所以被代理类不能是final修饰的,否则就无法继承,不能代理。
  72. 实现步骤:
  73. 0、先导入CGLIB依赖库。
  74. 1、定义没有接口的真实类,假如某个类没有实现任何接口
  75. 2、实现MethodInterceptor接口--处理代理逻辑
  76. CGLIB动态代理是使用MethodInterceptor接口定义代理的额外操作,核心的方法是intercept()方法
  77. intercept()方法包含4个参数:
  78. Object obj 代理对象,子类实例
  79. java.lang.reflect.Method method 当前调用的方法
  80. Object[] args 方法的参数
  81. MethodProxy proxy 方法的代理对象(用来调用父类的方法)
  82. 3、生成代理类对象并且进行测试,过增强器对象Enhancer,生成代理类
  83. 动态代理的优缺点:
  84. 优点:不需要手动编写代理类、可以批量处理多个类,比如给所以方法统一添加日志,灵活性很高。
  85. 缺点:逻辑相比静态代理要复杂一些,理解难度也高一些。
  86. JDK动态代理只能代理接口及其实现类。CGLIB需要依赖第三方库,而且不能代理final类。
  87. 使用代理模式的场景:
  88. Spring AOP面向切面编程,核心就是动态代理。
  89. 日志框架,通过代理模式给所有的方法都自动添加日志输出
  90. 权限控制,每当调用一些敏感方法之前,都是通过代理验证用户的权限。
  91. 缓存,在调用方法之前,可以通过代理检查缓存,避免重复计算。