1.概念

①介绍

二十三种设计模式中的一种,属于结构型模式。它的作用就是通过提供一个代理类,让我们在调用目标方法的时候,不再是直接对目标方法进行调用,而是通过代理类间接调用。让不属于目标方法核心逻辑的代码从目标方法中剥离出来——解耦。调用目标方法时先调用代理对象的方法,减少对目标方法的调用和打扰,同时让附加功能能够集中在一起也有利于统一维护。img004.e76b3080.png
使用代理后:
img005.74dd7746.png

②生活中的代理

  • 广告商找大明星拍广告需要经过经纪人
  • 合作伙伴找大老板谈合作要约见面时间需要经过秘书
  • 房产中介是买卖双方的代理
  • 太监是大臣和皇上之间的代理

    ③相关术语

  • 代理:将非核心逻辑剥离出来以后,封装这些非核心逻辑的类、对象、方法。

  • 目标:被代理“套用”了非核心逻辑代码的类、对象、方法。

    理解代理模式、AOP的核心关键词就一个字:

2、静态代理

3、动态代理

img003.2fe524a2.png

①生产代理对象的工厂类

  1. / 泛型T要求是目标对象实现的接口类型,本代理类根据这个接口来进行代理
  2. public class LogDynamicProxyFactory<T> {
  3. // 将被代理的目标对象声明为成员变量
  4. private T target;
  5. public LogDynamicProxyFactory(T target) {
  6. this.target = target;
  7. }
  8. public T getProxy() {
  9. // 创建代理对象所需参数一:加载目标对象的类的类加载器
  10. ClassLoader classLoader = target.getClass().getClassLoader();
  11. // 创建代理对象所需参数二:目标对象的类所实现的所有接口组成的数组
  12. Class<?>[] interfaces = target.getClass().getInterfaces();
  13. // 创建代理对象所需参数三:InvocationHandler对象
  14. // Lambda表达式口诀:
  15. // 1、复制小括号
  16. // 2、写死右箭头
  17. // 3、落地大括号
  18. InvocationHandler handler = (
  19. // 代理对象,当前方法用不上这个对象
  20. Object proxy,
  21. // method就是代表目标方法的Method对象
  22. Method method,
  23. // 外部调用目标方法时传入的实际参数
  24. Object[] args)->{
  25. // 我们对InvocationHandler接口中invoke()方法的实现就是在调用目标方法
  26. // 围绕目标方法的调用,就可以添加我们的附加功能
  27. // 声明一个局部变量,用来存储目标方法的返回值
  28. Object targetMethodReturnValue = null;
  29. // 通过method对象获取方法名
  30. String methodName = method.getName();
  31. // 为了便于在打印时看到数组中的数据,把参数数组转换为List
  32. List<Object> argumentList = Arrays.asList(args);
  33. try {
  34. // 在目标方法执行前:打印方法开始的日志
  35. System.out.println("[动态代理][日志] " + methodName + " 方法开始了,参数是:" + argumentList);
  36. // 调用目标方法:需要传入两个参数
  37. // 参数1:调用目标方法的目标对象
  38. // 参数2:外部调用目标方法时传入的实际参数
  39. // 调用后会返回目标方法的返回值
  40. targetMethodReturnValue = method.invoke(target, args);
  41. // 在目标方法成功后:打印方法成功结束的日志【寿终正寝】
  42. System.out.println("[动态代理][日志] " + methodName + " 方法成功结束了,返回值是:" + targetMethodReturnValue);
  43. }catch (Exception e){
  44. // 通过e对象获取异常类型的全类名
  45. String exceptionName = e.getClass().getName();
  46. // 通过e对象获取异常消息
  47. String message = e.getMessage();
  48. // 在目标方法失败后:打印方法抛出异常的日志【死于非命】
  49. System.out.println("[动态代理][日志] " + methodName + " 方法抛异常了,异常信息是:" + exceptionName + "," + message);
  50. }finally {
  51. // 在目标方法最终结束后:打印方法最终结束的日志【盖棺定论】
  52. System.out.println("[动态代理][日志] " + methodName + " 方法最终结束了");
  53. }
  54. // 这里必须将目标方法的返回值返回给外界,如果没有返回,外界将无法拿到目标方法的返回值
  55. return targetMethodReturnValue;
  56. };
  57. // 创建代理对象
  58. T proxy = (T) Proxy.newProxyInstance(classLoader, interfaces, handler);
  59. // 返回代理对象
  60. return proxy;
  61. }
  62. }