设计模式(11) - 结构型模式 - 代理模式!!!

0. 前言

动态代理是非常的厉害啊,想当初学习mybatis的时候,被 只写接口就能直接使用的情况 惊艳到了。当初想,为什么能这么厉害?这么神奇吗?哈哈,这就是动态代理的功劳了!非常的强大!。当然还有其他的,比如aop啊啥的。

1. 代理模式介绍

1.1 定义

为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。

1.2 应用场景

  • AOP(本文以此为例)
  • 延迟加载: 一开始不去初始化“被代理对象”,用代理对象去代替“被代理对象”的位置,当用到的时候,代理对象在去初始化“被代理对象”,体现了“注重对对象的控制”
  • 远程代理
  • 等等等

1.3 分类

  • 静态代理(感觉不经常用)
  • 动态代理(比较重要)

1.4 与装饰模式的区别

  • 代理:

    • 注重对象的控制
  • 装饰:

    • 注重对象的增强
  • 啥意思呢?
    用装饰模式的情况下,你肯定是要用到被装饰对象的方法,在此方式下进行增强。且增强的与原来的功能一定是有密切联系的。
    比如你用BufferedReader去装饰FileReadef。增强了其read方法,使其可以读一行,这增强的方法显然与被增强的方法有很强的关联。
    反观代理模式中的扩展功能则不同 比如在方法的前面和后面打印日志,可以发现打印日志跟原来的方法没有很强的联系。并且装饰模式还可以层层装饰。

    其实总的来说,不用纠结了,基本上感觉用代理模式,也是去用动态代理,而纠结的是装饰模式与静态代理的区别。我就想问,动态代理能干的事儿,装饰模式行吗?
    所以,就不用太纠结。

    代理模式下,什么时候创建 被代理对象? 代理实现的这个功能可能调用了被代理对象的一个方法,或者两个,或者有时间一个,有时候两个。所以来说,代理模式强调的是对象的控制。

2. 静态代理

静态代理,就是代理类是自己写死的,灵活性比较差
换句话说:在程序运行前就已经存在代理类的字节码文件,代理类和被代理类的关系在运行前就确定了。

2.1 场景介绍

场景很直白,如下:
我UserService 里面有一个save方法,用来保存的, 是几个月前写的。
现在需求变更来了,突然新来了一个需求,要求我们吧所有的UserService的save方法执行保存之前都要进行一个日志的记录。
那在不更改原来代码的前提下,就用到了代理模式(装饰模式也可以),代理一下原来的UserService对象,在UserService对象种的save方法执行之前,先输出日志。

2.2 类图

在这里插入图片描述

2.3 代码

  • step1 接口代码:
    在这里插入图片描述

  • step2 被代理类代码:
    在这里插入图片描述

  • setp3 代理类代码:
    在这里插入图片描述

  • setp4 调用代码
    在这里插入图片描述

2.4 优缺点

2.4.1 静态代理的优点

可以实现Client与被代理类类间的 解耦,在不修改被代理类代码的情况下能够做一些额外的处理。此优点代理模式都有,不管动态or静态

2.4.2 静态代理的缺点

缺点可想而知,从上面的代码可以的明显的发现。

缺点1: 代码重复,维护复杂 请看下图解释
在这里插入图片描述
缺点2: 存在类爆炸的可能

不知道有没有发现, 我对UserService进行了代理,我写了一个UserServiceProxy的一个代理类,那么在实际情况中,你可能就一个UserService ? 那不应该吧,你对UserService 的save方法进行增强。写了一个UserService的代理类,那么其他的Service的save 方法也得弄,那不就直接裂开了吗?😂

3. 动态代理(Jdk为例)

动态代理,就是呀,这个代理类,不是我们自己一开始写死的,而是动态生成的。非常的强,解决了上面静态代理的很多缺点。

注意一点,jdk的动态代理,被代理的类一定是要实现某个接口的。不然生成的代理类的时候 jdk不知道要对此代理类生成什么方法

(换个意思说,就是被代理类实现了某几个接口,那么你一定有这几个接口里面的方法。那么我jdk代理你这个类的时候,我也实现被代理类实现的这几个接口,我自然而然的就知道了你这个被代理类里面 一定有接口里面的这几个方法,那么我不就间接有被代理类中的方法了吗?)。
具体意思,(见3.4节)。

当然除了jdk的动态代理,还有cglib动态代理,这个cglib动态代理到是不用 被代理类实现什么接口。但是cglib也是要知道你有什么方法呀,所以cglib生成的代理类,是通过继承的方式来获得 被代理类的方法的。所以你被代理类一定不能是final类,你如果是final类,人家怎么通过继承 获得你里面有什么方法鸭。

3.1 代码

相信看这个的人,都会写jdk的动态代理,我就不介绍咋用了。

  • step1: 接口代码:
    在这里插入图片描述

  • step2: 实现类代码:
    在这里插入图片描述

  • step3: InvocationHandler代码:
    在这里插入图片描述

  • step4: 工厂

    为了解耦,我随便写了一个工厂。看情况写吧,不重要

    在这里插入图片描述

  • step5 : Client代码
    在这里插入图片描述

  • step6: 执行结果
    在这里插入图片描述

3.2 优点

  • 静态代理一个代理只能代理一种类型。动态代理是在运行时,通过反射机制实现代理对象的生成,并且能够代理各种类型的对象。意思看下图
    • 在这里插入图片描述
  • 接口中声明的所有方法都被集中到InvocationHandler.invoke()方法中去处理,大大提高了灵活性,指责更加单一。具体可看下图(方法来自InvocationHandler,详情看上面代码)
    • 在这里插入图片描述

3.3 动态生成的代理类长什么样?

生成的代理类 长的什么样子?其内部执行的逻辑又是什么样子的?
我这边将代理类输出到了磁盘上,用Idea打开了。Idea可以自动反编译的。
其代码如下

在这里插入图片描述

3.4 生成的动态代理类执行分析。

生成的代理类是如何运作的?看下图 请按照数字标号看

在这里插入图片描述

3.5 “代理类生成” 的jdk源码执行过程(略) 有机会在写一篇

略略略略。

4. 总结

写这个花费了不少时间呢,总之可能看了这个,可能也不会懂什么,最主要的还是要自己体验吧。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值