代理模式的理解(以静态代理为例)

image.png
代理模式可以看作对目标类的包装,1. 目标实例作为代理实例的属性(即绑定),2. 代理类的接口和目标类的接口是对接的(比如目标类实现了代理类的接口),3. 其次代理类可以实现额外的功能。

  • 案例:创建多线程中,Thread类就是代理类,它不但使用了执行了当前实例的功能,而且做了线程管理等扩展。作为开发者,我们不需要操心如何管理线程等细节,就可以实现多线程执行。

image.png

静态代理的缺点:代理类和被代理类都在编译期间被确定下来,不利于程序的进一步扩展,比如被代理类越多就需要越多的代理类。

动态代理特点:在运行期才确定代理类和被代理类,并且一个代理类就可以完成全部的代理工作。(通过反射实现,解决静态代理的缺点)

下图中。在编译阶段,通用代码的逻辑实现是确定的,而部分逻辑实现是不确定的,当运行阶段时,我们才确定逻辑实现。

image.png

代码

需求:在排序任务中,具体使用什么排序方法是随机的,但是其他代码部分是通用的。

下面代码放置于包 com.xj.java下,执行SortTask.java文件。 SortTask.java是使用动态代理实现的任务逻辑代码 , Sort.java是具体排序方法的实现,Util.java是通用代码的实现。
整体逻辑是,我希望在排序任务的处理中,通用代码是固定的,但是排序的核心算法是动态选择的。 核心代码块即class ProxyFactoryclass MyInvocationHandler implements InvocationHandler,因为它们解决了两个实现动态代理的关键问题(见下SortTask.java)。
Sort.javaSortTask.javaUtil.java

SortTask.java

要想实现动态代理,注意下面解决的问题?
问题一:如何根据加载到内存中的被代理类,动态的创建一个代理类及其对象。class ProxyFactory
问题二:当通过代理类的对象调用方法a时,如何动态的去调用被代理类中的同名方法a。class MyInvocationHandler implements InvocationHandler

  1. package com.xj.java;
  2. import java.lang.reflect.InvocationHandler;
  3. import java.lang.reflect.Method;
  4. import java.lang.reflect.Proxy;
  5. import java.util.Random;
  6. /**
  7. * @author jia
  8. * @create 2021-12-22 2:49 下午
  9. *
  10. * 要想实现动态代理,需要解决的问题?
  11. * 问题一:如何根据加载到内存中的被代理类,动态的创建一个代理类及其对象。
  12. * 问题二:当通过代理类的对象调用方法a时,如何动态的去调用被代理类中的同名方法a
  13. */
  14. public class SortTask {
  15. public static void main(String[] args) {
  16. // 随机选择排序的方法
  17. Sort proxyInstance = null;
  18. int t = new Random().nextInt(2);
  19. switch (t) {
  20. case 0:
  21. proxyInstance = (Sort)ProxyFactory.getProxyInstance(new QuickSort());
  22. case 1:
  23. proxyInstance = (Sort)ProxyFactory.getProxyInstance(new MergeSort());
  24. }
  25. // 执行排序任务
  26. proxyInstance.sort();
  27. }
  28. }
  29. class ProxyFactory{
  30. //调用此方法,返回一个代理类的对象。解决问题一
  31. public static Object getProxyInstance(Object obj){// obj:被代理类的对象
  32. MyInvocationHandler handler = new MyInvocationHandler();
  33. handler.bind(obj);
  34. // 当通过代理类对象调用方法时,会自动的调用被代理类中同名的方法
  35. return Proxy.newProxyInstance(obj.getClass().getClassLoader(),obj.getClass().getInterfaces(),handler);
  36. }
  37. }
  38. class MyInvocationHandler implements InvocationHandler {
  39. private Object obj;
  40. public void bind(Object obj){
  41. this.obj = obj;
  42. } // 赋值被代理类的实例
  43. // 当执行"代理类的对象.方法a"时,就会自动的调用如下的方法:invoke() 解决问题二
  44. // 本质是通过反射来调用被代理类的方法
  45. @Override
  46. public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
  47. Util util = new Util(); // AOP设计模式中,可以额外执行一些通用方法
  48. util.method1();
  49. // 核心处理过程
  50. Object returnValue = method.invoke(obj,args);
  51. util.method2();
  52. //返回invoke()的返回值。
  53. return returnValue;
  54. }
  55. }

这是排序任务的通用方法1 执行归并排序 这是排序任务的通用方法2

Sort.java

  1. package com.xj.java;
  2. /**
  3. * @author jia
  4. * @create 2021-12-22 3:09 下午
  5. */
  6. public interface Sort {
  7. public void sort();
  8. }
  9. class QuickSort implements Sort {
  10. @Override
  11. public void sort(){
  12. System.out.println("执行快速排序");
  13. }
  14. }
  15. class MergeSort implements Sort{
  16. @Override
  17. public void sort(){
  18. System.out.println("执行归并排序");
  19. }
  20. }

Util.java

  1. package com.xj.java;
  2. /**
  3. * @author jia
  4. * @create 2021-12-22 2:51 下午
  5. */
  6. public class Util {
  7. public void method1(){
  8. System.out.println("这是排序任务的通用方法1");
  9. }
  10. public void method2(){
  11. System.out.println("这是排序任务的通用方法2");
  12. }
  13. }