美文网首页
代理模式

代理模式

作者: zzj0990 | 来源:发表于2021-01-20 00:20 被阅读0次

今天特意将静态代理、JDK动态代理、CGLIB动态代理 和 String AOP整理如下,与各位看客分享下。

1. 代理概念

由于某些原因需要给某对象提供一个代理以控制对该对象的访问。
这时,访问对象不适合或者不能直接引用目标对象,代理对象作为访问对象和目标对象之间的中介。

2. 代理概述

主要优点:

  1. 代理模式在客户端与目标对象之间起到一个中介作用和保护目标对象的作用
  2. 代理对象可以扩展目标对象的功能
  3. 代理模式能将客户端与目标对象分离,在一定程度上降低了系统的耦合度,增加了程序的可扩展性

主要缺点:

  1. 代理模式会造成系统设计中类的数量增加
  2. 在客户端和目标对象之间增加一个代理对象,会造成请求处理速度变慢;
  3. 增加了系统的复杂度;
    以上缺点可以由动态代理来解决

3. 实例分析

屏幕快照 2021-01-19 下午3.42.13.png
  • 静态代理:
interface Movable {
    void move();
}
/**
 * 问题:我想记录坦克的移动时间
 * 最简单的办法:修改代码,记录时间
 * 问题2:如果无法改变方法源码呢?
 * 用继承?
 * v05:使用代理
 */
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();
        }
    }
}
class TankTimeProxy implements Movable 
    Movable movable;
    public TankTimeProxy(Movable movable) {
        this.movable = movable;
    }
    @Override
    public void move() {
        long start = System.currentTimeMillis();
        movable.move();
        long end = System.currentTimeMillis();
        System.out.println(end - start);
    }
}
public static void main(String[] args) {
        new TankTimeProxy(new Tank()).move();
    }

静态代理分析:代理类A要代理的类B时,同样要实现B类实现的接口一样,通过代理类的构造方法将被代理的类对象注入进来,然后再通过实现接口对B类方法进行扩展。
如果要实现多种类型的代理,则类的数量会扩展。

  • 动态代理:
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 static void main(String[] args) {
        Tank tank = new Tank();
        Movable m = (Movable)Proxy.newProxyInstance(Tank.class.getClassLoader(),  // 代理类,这里使用被代理的类
                new Class[]{Movable.class},                                       // 代理对象应该实现哪些接口
                new LogHander(tank)                                               // 被代理对象调用时的处理逻辑
        );

        m.move();
    }
}
class TimeProxy implements InvocationHandler {
    Movable m;
    public TimeProxy(Movable m) {
        this.m = m;
    }
    public void before() {
        System.out.println("method start..");
    }
    public void after() {
        System.out.println("method stop..");
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        before();
        Object o = method.invoke(m, args); // 被代理对象的操作
        after();
        return o;
    }
}

代理类是动态生成的,如下代码片段:

  • 图1:


    屏幕快照 2021-01-19 下午11.32.24.png
  • 图2:


    屏幕快照 2021-01-19 下午11.32.37.png
  • 图3:


    屏幕快照 2021-01-19 下午11.33.55.png
  • 图4:


    屏幕快照 2021-01-19 下午11.51.43.png
1.根据所传入的参数生成一个代理类
2.代理类实现了相关接口(Movable),继承了Proxy,其构造函数是有参构造,传入一个InvocationHandler。见图1, 3
3.所以,其使用代理类,调用方法move(),都会先调用InvocationHandler中的invoke方法,见图2
4.至于要不要调用代理类的方法,需要看,在invoke中是否调用了method.invoke(tank, args)。见图4
  • CGLIB动态代理:
public class Main {
    public static void main(String[] args) {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(Tank.class);
        enhancer.setCallback(new TimeMethodInterceptor()); // 相当于动态代理中的InvocationHandler
        Tank tank = (Tank)enhancer.create();
        tank.move();
    }
}
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 = null;
        result = methodProxy.invokeSuper(o, objects);
        System.out.println("after");
        return result;
    }
}
class Tank {
    public void move() {
        System.out.println("Tank moving claclacla...");
        try {
            Thread.sleep(new Random().nextInt(10000));
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
  • pom.xml添加配置:


    屏幕快照 2021-01-20 上午12.02.38.png
  • String AOP:

public class Tank {
    public void move() {
        System.out.println("Tank moving claclacla...");
        try {
            Thread.sleep(new Random().nextInt(10000));
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
<bean id="tank" class="com.mashibing.dp.spring.v1.Tank"/>
<bean id="timeProxy" class="com.mashibing.dp.spring.v1.TimeProxy"/>

    <aop:config>
        <aop:aspect id="time" ref="timeProxy">
            <aop:pointcut id="onmove" expression="execution(void com.mashibing.dp.spring.v1.Tank.move())"/>
            <aop:before method="before" pointcut-ref="onmove"/>
            <aop:after method="after" pointcut-ref="onmove"/>
        </aop:aspect>
    </aop:config>

注解的方式略,问度娘...

4. 总结

  1. 静态代理类型多的话,类的数量会膨胀。
  2. 动态代理要求被代理的对象必须实现接口,这是由proxy内部所决定的。
  3. CGLIB实现动态代理不需要接口,但final 类型的类无法实现动态(底层实现技术ASM)
  4. String AOP也是ASM实现的。

————————————————————
坐标帝都,白天上班族,晚上是知识的分享者
如果读完觉得有收获的话,欢迎点赞加关注

相关文章

  • 设计模式

    单例模式 模板方法模式 工厂模式 代理模式 静态代理 JDK动态代理

  • 设计模式

    单例模式 代理模式 静态代理 jdk动态代理 cglib动态代理 工厂模式 适配器模式 建造者模式 观察者模式

  • kube-proxy的3种模式

    userspace代理模式 iptables代理模式 IPVS代理模式 https://kubernetes.io...

  • 第4章 结构型模式-代理模式

    一、代理模式简介 二、代理模式3个角色 三、代理模式的优点 四、代理模式的实例(游戏代练)

  • 理解代理模式

    原创博客地址 简介 代理模式,也叫做委托模式,分为:静态代理动态代理 代理模式也是平时比较常用的设计模式之一,代理...

  • 结构型 代理模式(文末有项目连接)

    1:什么是代理模式 2:没用代理模式时的实例 3:使用代理模式将其解耦(静态代理) 3:使用代理模式将其解耦(动态...

  • 设计模式-动态代理模式

    之前介绍了代理模式,大家也都了解了代理模式,不过之前介绍的代理模式是静态代理,静态代理什么意思?静态代理指的是代理...

  • 代理模式

    一、什么是代理模式 代理模式(Proxy pattern):代理模式又叫委托模式,是为某个对象提供一个代理对象,并...

  • 设计模式之代理模式(Proxy模式)

    代理模式的引入 代理模式的实例程序 代理模式的分析 代理模式的引入 Proxy是代理人的意思,指的是代替别人进行工...

  • Java设计模式之代理模式

    Java设计模式之代理模式 代理模式 静态代理 动态代理 为什么需要代理 通过代理,我们能够不用知道委托人是谁,而...

网友评论

      本文标题:代理模式

      本文链接:https://www.haomeiwen.com/subject/bamaaktx.html