动态代理 静态代理

    概述;
    代理人帮被代理人做某件事,同时添加自己的操作
    代理行为,被代理人事件前后执行的操作

    聚合相比于继承的好处在于 可以公用 不会被某一类所限制

    类图:
    image.png

    静态代理
    代理对象/被代理对象 共同实现接口 代理类中聚合被代理对象实现的接口
    可以实现代理间灵活的嵌套
    image.png

    jdk动态代理

    目的:
    分离代理行为与被代理对象 可以代理各种类型 不在被聚合的接口所限制

    类图:
    两段:生成代理类的过程 调用的过程
    image.png
    用法
    通过 Proxy.newProxyInstance 自动生成
    可以通过方法:
    System.getProperties().put(“jdk.proxy.ProxyGenerator.saveGeneratedFiles”,”true”); 保存 自动生成的代理文件 $Proxy0.Class 文件 查看
    通过反编译可以看出
    $Proxy0 继承 Proxy 实现了 被代理类接口
    其中自动生成了 实现接口中的方法

    image.png
    h 为 父类Proxy中的 InvocationHandler 执行了 invoke 方法
    当新建代理对象 执行了 接口中的方法
    image.png

    image.png
    实际是 执行的自动生成的代理类中的 接口方法
    又自动调用了 InvocationHandler 中的 invoke 方法
    所以执行了 重写方法中的 invoke 方法
    image.png
    Object o = method.invoke(m, args);
    method 为接口中的方法,m 为引用(被代理对象)
    传入那个引用 就执行哪个引用实现的接口方法。

    1. public class Tank implements Movable {
    2. /**
    3. * 模拟坦克移动了一段儿时间
    4. */
    5. @Override
    6. public void move() {
    7. System.out.println("Tank moving claclacla...");
    8. try {
    9. Thread.sleep(new Random().nextInt(10000));
    10. } catch (InterruptedException e) {
    11. e.printStackTrace();
    12. }
    13. }
    14. public static void main(String[] args) {
    15. Tank tank = new Tank();
    16. //reflection 通过二进制字节码分析类的属性和方法
    17. Movable m = (Movable)Proxy.newProxyInstance(Tank.class.getClassLoader(),
    18. new Class[]{Movable.class}, //tank.class.getInterfaces()
    19. new LogHander(tank)
    20. );
    21. m.move();
    22. }
    23. }
    24. class LogHander implements InvocationHandler {
    25. Tank tank;
    26. public LogHander(Tank tank) {
    27. this.tank = tank;
    28. }
    29. //getClass.getMethods[]
    30. @Override
    31. public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    32. System.out.println("method " + method.getName() + " start..");
    33. Object o = method.invoke(tank, args);
    34. System.out.println("method " + method.getName() + " end!");
    35. return o;
    36. }
    37. }
    38. interface Movable {
    39. void move();
    40. }

    jdk动态代理
    最底层用的是 ObjectWeb包下的 ASM
    ASM可以直接造作二进制字节码文件

    cglib动态代理
    不需要被代理类实现接口

    代码举例
    image.png

    动态代理嵌套
    动态代理没有聚合被代理类实现的接口 如何实现代理嵌套
    动态代理的灵活性 只需要 在重写执行器方法时 将需要生成的代理类执行的方法切入就行