本笔记为本人在B站学习时整理而成,为了更好的学习,将其整理成笔记,以防忘记相关知识点。
代理模式
代理模式是指,为其他对象提供一种代理以控制对这个对象的访问。
在某些情况下, 一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户类和目标对象之 间起到中介的作用。
换句话说,使用代理对象,是为了在不修改目标对象的基础上,增强主业务逻辑。
客户类真正的想要访问的对象是目标对象,但客户类真正可以访问的对象是代理对象。
客户类对目标对象的访问是通过访问代理对象来实现的。
当然,代理类与目标类要实现同一个接口。
例如: 有 A,B,C 三个类, A 原来可以调用 C 类的方法
, 现在因为某种原因 C 类不允许A 类调用其方法
,
但 B 类可以调用 C 类的方法
。A 类通过 B 类调用 C 类的方法
。这里 B 是 C 的代理
。 A 通过代理 B 访问 C
。
原来的访问关系:
1 | A类-----可以访问------->C类 |
通过代理的访问关系:
1 | A类-----不可以访问------>C类 |
Window 系统的快捷方式也是一种代理模式。快捷方式代理的是真实的程序,双击快捷方式是启动它代表的程序。
使用代理模式的作用
(1)功能增强
: 在你原有的功能上,增加了额外的功能,新增加的功能,叫做功能增强。
(2)控制访问
: 代理类不让你访问目标,例如商家不让用户访问厂家。
代理模式分类
可以将代理分为两类:静态代理与动态代理
。
静态代理
1) 代理类是自己手工实现的,自己创建一个java类,表示代理类。
2)同时你所要代理的目标类是确定的。
特点:
1)实现简单 2)容易理解。
模拟一个用户购买u盘的行为
用户是客户端类
商家:代理,代理某个品牌的u盘。
厂家:目标类。
三者的关系:
用户(客户端)—商家(代理)—厂家(目标)
商家和厂家都是卖u盘的,他们完成的功能是一致的,都是卖u盘。
实现步骤:
- 创建一个接口,定义卖u盘的方法, 表示你的厂家和商家做的事情。
- 创建厂家类,
实现1步骤的接口
。 - 创建商家,就是代理,
也需要实现1步骤中的接口
。 - 创建客户端类,调用商家的方法买一个u盘。
实现
(1)定义业务接口
1 | package com.kwxy.service; |
(2)定义接口实现类
目标类 UsbKingFactory(金士顿 u 盘),该类实现了业务接口。
1 | package com.kwxy.factory; |
(3)代理商TaoBao
TaoBao 就是一个代理类, 代理厂家销售 u 盘
1 | package com.kwxy.shangjian; |
(4)代理商WeiShang
WeiShang 就是一个代理类, 代理厂家销售 u 盘。
1 | package com.kwxy.shangjian; |
(5)客户端调用者,购买商品类
1 | package com.kwxy; |
(5)如果目标类增加了,比如增加了一个闪迪厂家
1 | package com.kwxy.factory; |
(6)还得重新增加闪迪的TaoBao和WeiShang代理类
1 | package com.kwxy.shangjian; |
1 | package com.kwxy.shangjian; |
缺点
当你的项目中,目标类和代理类很多时候,有以下的缺点:
(1)当目标类增加了, 代理类可能也需要成倍的增加。 代理类数量过多。
(2) 当你的接口中功能增加了, 或者修改了,会影响众多的实现类,厂家类,代理都需要修改。影响比较多。
代理类完成的功能
(1)目标类中方法的调用
(2)功能增强
动态代理
动态代理是指代理类对象在程序运行时由 JVM 根据反射机制
动态生成的。动态代理不需要定义代理类的.java 源文件。
动态代理其实就是 jdk 运行期间,动态创建 class 字节码并加载到 JVM。
动态代理的实现方式常用的有两种:使用 JDK 动态代理
,与通过 CGLIB 动态代理
。
在静态代理中目标类很多时候,可以使用动态代理,避免静态代理的缺点。
动态代理中目标类即使很多:
1)代理类数量可以很少。
2)当你修改了接口中的方法时,不会影响代理类。
jdk动态代理(理解)
使用java反射包中的类和接口实现动态代理的功能。
反射包 java.lang.reflect , 里面有三个类 : InvocationHandler
,Method
,Proxy
。
jdk 动态代理是基于 java 的反射机制实现的。使用 jdk 中接口和类实现代理对象的动态创建。
jdk 的动态要求目标对象必须实现接口,这是 java 设计上的要求。
InvocationHandler 接口
InvocationHandler 接口叫做调用处理器,负责完调用目标方法,并增强功能。
通 过代理对象执行目标接口中的方法,会把方法的调用分派给调用处理器(InvocationHandler)的实现类,
执行实现类中的 invoke()方法,我们需要把功能代理写在 invoke ()方法中 。
public Object invoke(Object proxy, Method method, Object[] args)
方法原型:
参数:
Object proxy
:jdk创建的代理对象,无需赋值。
Method method
:目标类中的方法,jdk提供method对象的
Object[] args
:目标类中方法的参数, jdk提供的。
InvocationHandler 接口:表示你的代理要干什么。
怎么用:
(1)创建类实现接口InvocationHandler
(2)重写invoke()方法, 把原来静态代理中代理类要完成的功能,写在这。
Method类
表示方法的, 确切的说就是目标类中的方法。
InvocationHandler中的invoke()方法的第二个参数为 Method 类对象,该类有一个方法也叫 invoke()
,可以调用 目标方法。
这两个 invoke()方法,虽然同名,但无关
。
public Object invoke ( Object obj, Object... args)
obj:
表示目标对象
args:
表示目标方法参数,就是其上一层 invoke 方法的第三个参数
该方法的作用是:
调用执行 obj 对象所属类的方法,这个方法由其调用者 Method 对象确定。
在代码中,一般的写法为 method.invoke(target, args);
Proxy 类
通 过 JDK 的 java.lang.reflect.Proxy 类实现动态代理 ,会使用其静态方法 newProxyInstance(),依据目标对象、业务接口及调用处理器三者,自动生成一个动态代理对象。
之前创建对象都是 new 类的构造方法(),现在我们是使用Proxy类的方法,代替new的使用。
public static Object newProxyInstance(
ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler handler)
ClassLoader loader
:类加载器,负责向内存中加载对象的。 使用反射获取对象的ClassLoader。
Class<?>[] interfaces
: 接口数组, 目标对象实现的接口,也是反射获取的。
InvocationHandler handler
:我们自己写的,代理类要完成的功能。
返回值:就是代理对象。
cgLib代理(了解)
cglib动态代理(了解): cglib是第三方的工具库, 创建代理对象。
cglib的原理是继承, cglib通过继承目标类,创建它的子类,在子类中重写父类中同名的方法, 实现功能的修改。
因为cglib是继承,重写方法,所以要求目标类不能是final的, 方法也不能是final的。
cglib的要求目标类比较宽松, 只要能继承就可以了。cglib在很多的框架中使用,
比如 mybatis ,spring框架中都有使用。
但对于无接口的类,要为其创建动态代理,就要使用 cglib来实现。
对 于 cglib 一般的开发中并不使用。做了一个了解就可以。
jdk 动态代理实现
实现动态代理的步骤:
1 | 1. 创建接口,定义目标类要完成的功能 |
参考代码:
(1)创建接口,定义目标类要完成的功能
1 | package com.kwxy.service; |
(2)创建目标类实现接口
1 | package com.kwxy.factory; |
(3)创建InvocationHandler接口的实现类,在invoke方法中完成代理类的功能
1 | package com.kwxy.handler; |
使用步骤:
(1)创建目标对象。
(2)创建InvocationHandler对象。
(3)使用Proxy类的静态方法,创建代理对象,并把返回值转为接口类型。
(4)通过代理执行方法。
1 | package com.kwxy; |
发布时间: 2020-07-24
最后更新: 2023-01-27
本文标题: 动态代理学习笔记
本文链接: https://blog-yilia.xiaojingge.com/posts/d48ff860.html
版权声明: 本作品采用 CC BY-NC-SA 4.0 许可协议进行许可。转载请注明出处!
