九折技术 九折技术
首页
  • Go
  • MIT-6824
  • 算法与数据结构
  • 面向对象
  • 代码整洁
  • 重构
  • 设计模式
  • 学习
  • 技术
  • 人文
关于
  • 网站
  • 资源
  • 分类
  • 标签
  • 归档
GitHub

HoldDie

长期有耐心,一切才刚刚开始!
首页
  • Go
  • MIT-6824
  • 算法与数据结构
  • 面向对象
  • 代码整洁
  • 重构
  • 设计模式
  • 学习
  • 技术
  • 人文
关于
  • 网站
  • 资源
  • 分类
  • 标签
  • 归档
GitHub
  • 代码整洁

  • 重构

  • 设计模式

    • 创建型-单例模式
    • 创建型-工厂模式
    • 创建型-建造者模式
    • 创建型-原型模式
    • 结构型-代理模式
      • 结构型-桥接模式
      • 结构型-装饰器模式
      • 结构型-适配器模式
      • 结构型-门面模式
      • 结构型-组合模式
      • 结构型-享元模式
      • 行为型-观察者模式
      • 行为型-模板模式
      • 行为型-策略模式
      • 行为型-责任链模式
      • 行为型-状态模式
      • 行为型-迭代器模式
      • 行为型-访问者模式
      • 行为型-备忘录模式
      • 行为型-命令模式
      • 行为型-解释器模式
      • 行为型-中介模式
    • 架构
    • 设计模式
    holddie
    2020-08-30

    结构型-代理模式

    # 什么是代理模式

    • 在不改变原始类代码的情况下,通过引入代理类来给原始类附加功能。
    • 日常开发过程中,通过代理模式,我们可以实现一些和业务无关的公共功能,例如方法执行时间、日志计算等。

    # 为什么使用代理模式

    • 添加一些特定功能,对原有的业务代码侵入性小。
    • 更好的可扩展性

    # 代理分类

    • 静态代理

    • 动态代理

      • JDK 动态代理(基于接口)
      • cglib 动态代理(采用继承)
      • 无论使用 JDK 动态代理还是 cglib 动态代理,底层都是使用 asm 实现。

    # 代理模式使用场景

    • 可以实现实现一些非功能性需求:监控、统计、鉴权、限流、事务、幂等、日志。
    • RPC 框架也可以看做一种代理模式,使得 RPC 服务的开发者也只需要开发业务逻辑,就像开发本地使用的函数一样,不需要关注跟客户端的交互细节。
    • Spring AOP 底层的实现原理就是动态代理
      • 基于 AOP 切面实现缓存功能
      • 对于数据库操作事务控制

    # 代理模式场景练习

    • 需求:加入我们想统计某方法的执行时间。

      • 第一种,最简单可以想到的就是直接在对应的代码前后使用时间计数做相减操作即可实现。
    • 如果所在方法源码不允许修改,可以想到使用继承或者实现相同接口

      • 一、继承原先的类,重写对应方法,添加时间统计功能

      • 二、实现要代理的方法的对应的接口,但是此时同时需要接口对应其他方法,很繁琐。

    • 如果此时不仅想统计执行时间,还想在执行前后打一些 log,如何实现代理的各种组合?继承?Decorator?

      • 代理对象改成特定类型,然后进行不同的代理类之间的嵌套,类似装饰者模式
    • 如果想让对应的代理行为功能和代理对象分离

      • 使用 JDK 动态代理
      • Cglib 动态代理
      • spring AOP 代理

    # 静态代理模式

    public interface Movable {
      void move();
    }
    
    public class Tank implements Movable {
      @Override
      public void move() {
        System.out.println("Tank moving claclacla...");
        try {
          Thread.sleep(new Random().nextInt(10000));
        } catch (InterruptedException e) {
          e.printStackTrace();
        }
      }
    }
    
    public class TankLogProxy implements Movable {
      public TankLogProxy(Movable movable) {
        this.movable = movable;
      }
    
      private final Movable movable;
    
      @Override
      public void move() {
        System.out.println("start moving.....");
        movable.move();
        System.out.println("end moving...");
      }
    }
    
    public class TankTimeProxy implements Movable {
      public TankTimeProxy(Movable movable) {
        this.movable = movable;
      }
    
      private final Movable movable;
    
      @Override
      public void move() {
        long start = System.currentTimeMillis();
        movable.move();
        long end = System.currentTimeMillis();
        System.out.println(end - start);
      }
    }
    
    public class Main {
      public static void main(String[] args) {
        Tank tank = new Tank();
        TankTimeProxy tankTimeProxy = new TankTimeProxy(tank);
        TankLogProxy tankLogProxy = new TankLogProxy(tankTimeProxy);
        tankLogProxy.move();
      }
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55

    # JDK 动态代理

    public interface Movable {
      void move();
    }
    
    public class Tank implements Movable {
      @Override
      public void move() {
        System.out.println("Tank moving claclacla...");
        try {
          Thread.sleep(new Random().nextInt(10000));
        } catch (InterruptedException e) {
          e.printStackTrace();
        }
      }
    }
    
    public class TimeProxy implements InvocationHandler {
      public TimeProxy(Movable movable) {
        this.movable = movable;
      }
    
      Movable movable;
    
      public void before() {
        System.out.println("Before");
      }
    
      public void after() {
        System.out.println("After");
      }
    
      @Override
      public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        before();
        Object object = method.invoke(movable, args);
        after();
        return object;
      }
    }
    
    public class Main {
      public static void main(String[] args) {
        Tank tank = new Tank();
        System.getProperties().setProperty("jdk.proxy.ProxyGenerator.saveGeneratedFiles", "true");
        Movable movable = (Movable) Proxy.newProxyInstance(Tank.class.getClassLoader(),
                                                           new Class[]{Movable.class},
                                                           new TimeProxy(tank)
                                                          );
        movable.move();
      }
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51

    # Java 动态代理调用流程

    image-20200831101721514

    # Cglib 动态代理

    public class Tank {
      public void move() {
        System.out.println("Tank moving claclacla...");
        try {
          Thread.sleep(new Random().nextInt(10000));
        } catch (InterruptedException e) {
          e.printStackTrace();
        }
      }
    }
    
    public class TimeMethodInterceptor implements MethodInterceptor {
      @Override
      public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println(o.getClass().getSuperclass().getName());
        System.out.println("Before");
        Object result = methodProxy.invokeSuper(o, objects);
        System.out.println("After");
        return result;
      }
    }
    
    public class Main {
      public static void main(String[] args) {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(Tank.class);
        enhancer.setCallback(new TimeMethodInterceptor());
        Tank tank = (Tank) enhancer.create();
        tank.move();
      }
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31

    # SpringAop 动态代理

    public class Tank {
      public void move() {
        System.out.println("Tank moving claclacla...");
        try {
          Thread.sleep(new Random().nextInt(10000));
        } catch (InterruptedException e) {
          e.printStackTrace();
        }
      }
    }
    
    public class TankTimeProxy {
    
    
      public void before() {
        System.out.println("before");
      }
    
      public void after() {
        System.out.println("after");
      }
    }
    
    public class Main {
      public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("app.xml");
        Tank tank = (Tank) context.getBean("tank");
        tank.move();
      }
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30

    # app.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xmlns:aop="http://www.springframework.org/schema/aop"
           xsi:schemaLocation="http://www.springframework.org/schema/beans
                               http://www.springframework.org/schema/beans/spring-beans-4.2.xsd
                               http://www.springframework.org/schema/aop
                               http://www.springframework.org/schema/aop/spring-aop-4.2.xsd">
    
      <bean id="tank" class="com.holddie.design.proxy.springAop.v1Xml.Tank"/>
      <bean id="timeProxy" class="com.holddie.design.proxy.springAop.v1Xml.TankTimeProxy"/>
    
      <aop:config>
        <aop:aspect id="time" ref="timeProxy">
          <aop:pointcut id="tankMoving"
                        expression="execution(void com.holddie.design.proxy.springAop.v1Xml.Tank.move())"/>
          <aop:before method="before" pointcut-ref="tankMoving"/>
          <aop:after method="after" pointcut-ref="tankMoving"/>
        </aop:aspect>
      </aop:config>
    </beans>
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    编辑
    #代理模式
    上次更新: 2020/09/08, 15:09:00
    创建型-原型模式
    结构型-桥接模式

    ← 创建型-原型模式 结构型-桥接模式→

    最近更新
    01
    行为型-访问者模式
    11-24
    02
    行为型-备忘录模式
    11-24
    03
    行为型-命令模式
    11-24
    更多文章>
    Theme by Vdoing | Copyright © 2019-2020 HoldDie | MIT License
    • 跟随系统
    • 浅色模式
    • 深色模式
    • 阅读模式