文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

Java结构型模式之代理模式怎么实现

2023-07-05 04:25

关注

今天小编给大家分享一下Java结构型模式之代理模式怎么实现的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。

一.介绍

在代理模式(Proxy Pattern)属于结构型模式。在代理模式中,我们对一个对象提供一个代理对象,使用代理对象控制原对象的引用,目的是为了透明的控制对象访问

二.UML类图

Java结构型模式之代理模式怎么实现

三.代理模式分类

Java中的代理按照代理类生成时机不同分为静态代理和动态代理,静态代理的代理类在编译器就生成,而动态代理的代理类在Java运行时动态生成。动态代理又分为JDK代理和CGLib代理。

四.静态代理

业务代码

public interface Pay {    void pay();}//真实类class Alipay implements Pay {    @Override    public void pay() {        System.out.println("支付宝支付");    }}//代理类class AlipayProxy implements Pay{    //组合真实对象    private final Alipay alipay = new Alipay();    @Override    public void pay() {        long startTime = System.currentTimeMillis();        alipay.pay();        System.out.println("执行了" + (System.currentTimeMillis()-startTime) + "毫秒"); //支付宝支付 执行了0毫秒    }}

测试代码

public class Client {    public static void main(String[] args) {        new AlipayProxy().pay();    }}

五.静态代理的优缺点

优点

缺点

六.动态代理

为了弥补静态代理的缺点,引入了动态代理

JDK动态代理(利用Java提供的代理机制)

业务代码

public interface Pay {    void pay();}//真实类class Alipay implements Pay {    @Override    public void pay() {        System.out.println("支付宝支付");    }}class PayProxy {    //组合真实对象    private Pay pay;    public PayProxy(Pay pay) {        this.pay = pay;    }    public Pay getProxy() {        return (Pay) Proxy.newProxyInstance(getClass().getClassLoader(), pay.getClass().getInterfaces(), new InvocationHandler() {            @Override            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {                long startTime = System.currentTimeMillis();                Object result = method.invoke(pay, args);                System.out.println("执行了" + (System.currentTimeMillis() - startTime) + "毫秒");                return result;            }        });    }}

测试代码

public class Client {    public static void main(String[] args) {        PayProxy payProxy = new PayProxy(new Alipay());        Pay pay = payProxy.getProxy();        pay.pay(); //支付宝支付 执行了0毫秒    }}

我们通过arthas工具进行反编译,可以找到真正的代理类$Proxy0

//代理对象public final class $Proxy0 extends Proxy implements Pay {    private static Method m3;    public $Proxy0(InvocationHandler invocationHandler) {        super(invocationHandler);    }    static {        // 通过反射获取名叫pay的menthod        m3 = Class.forName("com.designpattern.structure.proxy.v2.Pay").getMethod("pay", new Class[0]);        return;    }    public final void pay() {        // h是invocationHandler对象        this.h.invoke(this, m3, null);        return;    }}

总结执行流程如下

  1. 测试代码里执行了pay.pay()

  2. 根据多态的特性,执行的是代理类($Proxy0)中的pay方法

  3. 代理类($Proxy0)中的pay方法中执行了invocationHandler对象的invoke方法

  4. invocationHandler对象的invoke方法就是业务代码中传入的匿名内部类中重写的invoke方法

  5. 在重写的invoke方法中通过反射调用真实对象alipay的pay方法

CGLib动态代理

JDK动态代理要求必须定义接口,如果没有定义接口,就可以使用CGLib动态代理,CGLib为JDK的动态代理提供了很好的补充

首先引入cglib-3.3.0.jar与asm-9.0.jar

业务代码

//真实对象class Alipay implements Pay {    @Override    public void pay() {        System.out.println("支付宝支付");    }}class AlipayProxy implements MethodInterceptor {    //组合真实对象    private Alipay alipay = new Alipay();    public Alipay getProxy(){        Enhancer enhancer = new Enhancer();        enhancer.setSuperclass(Alipay.class);        //设置回调函数        enhancer.setCallback(this);        //返回代理对象        return (Alipay) enhancer.create();    }    @Override    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {        long startTime = System.currentTimeMillis();        Object result = method.invoke(alipay, args);        System.out.println("执行了" + (System.currentTimeMillis() - startTime) + "毫秒");        return result;    }}

测试代码

public class Client {    public static void main(String[] args) {        Alipay proxy = new AlipayProxy().getProxy();        proxy.pay(); //支付宝支付 执行了0毫秒    }}

七.JDK代理与CGLIB代理对比

八.代理模式的优缺点

优点

缺点

九.使用场景

功能扩展:日志、监控、事务

控制管理:权限、限流

远程代理:FeignClient、RMI

动态逻辑:mybatis mapper、jpa

延迟加载:虚代理

十.通用的动态代理实现(拓展)

上文提到静态代理是一个具体类产生一个代理类,可能会造成类爆炸,我们现在反观动态代理则是一个接口产生一个代理类,也可能会造成类爆炸,所以这里给出一个较为通用的实现

业务代码

//记录执行的时间的通用类public class TimeRecordProxy<T> {    private final T target;    public TimeRecordProxy(T target) {        this.target = target;    }    @SuppressWarnings("unchecked")    public T getProxy() {        return (T) Proxy.newProxyInstance(this.getClass().getClassLoader(),                target.getClass().getInterfaces(),                this::invoke);    }    private Object invoke(Object proxy, Method method, Object[] args) throws InvocationTargetException, IllegalAccessException {        long startTime = System.currentTimeMillis();        Object result = method.invoke(target, args);        System.out.println("执行了" + (System.currentTimeMillis()-startTime) + "毫秒");        return result;    }}

测试代码

public class Client {    public static void main(String[] args) {        TimeRecordProxy<Pay> timeRecordProxy = new TimeRecordProxy<>(new Alipay());        timeRecordProxy.getProxy().pay(); //支付宝支付 执行了0毫秒    }}

以上就是“Java结构型模式之代理模式怎么实现”这篇文章的所有内容,感谢各位的阅读!相信大家阅读完这篇文章都有很大的收获,小编每天都会为大家更新不同的知识,如果还想学习更多的知识,请关注编程网行业资讯频道。

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯