代理的概述
代理:给目标对象提供一个代理对象,并且由代理对象控制着对目标对象的引用(跟多态一样)
mybatis、spring都运用了代理机制
跳过创建类的过程,直接产生对象
简单来说,我们使用代理对象来代替对真实对象的访问,这样就可以在不修改原目标对象的前提下,提供额外的操作功能,扩展目标对象的功能
通俗的说,对象嫌身上干的事情太多,就需要通过代理来转移部分职责(意思就是尽量保证单一职责)。同时,对象有什么方法,代理就一定要有对应的方法
代理模式的主要作用是扩展目标对象的功能,比如说在目标对象的某个方法执行前后你可以增加一些自定义的操作
- 代理的实现
- 基于JDK的代理
- 静态代理
-
在静态代理中,我们对目标对象的每个方法的增强都是手动完成的(后面会具体演示代码),非常不灵活(比如接口一旦新增加方法,目标对象和代理对象都要进行修改)且麻烦(需要对每个目标类都单独写一个代理类)。从 JVM 层面来说, 静态代理在编译时就将接口、实现类、代理类这些都变成了一个个实际的 class 文件。
-
代码展示
-
//首先,我们要写出联系代理类与目标类的桥梁,接口 public interface BuyClothes {public void clothes(String size); } //然后我们写出目标类,这里用ClothedFactory为例 public class ClothesFactory implements BuyClothes{@Overridepublic void clothes(String size) {System.out.println("已经为您定制好了大小为" + size +"的衣服");} } //写出静态代理类 public class StaticProxy implements BuyClothes {private ClothesFactory clothesFactory = new ClothesFactory();//重写核心方法@Overridepublic void clothes(String size) {//代理类与目标类建立起了桥梁clothesFactory.clothes(size);} } //模拟用户方面 public class Test {public static void main(String[] args) {StaticProxy staticProxy = new StaticProxy();//此处,用户访问目标类的路径:用户-->代理类StaticProxy---(以共同接口BuyClothes为中间节点)--->目标类ClothesFactory-->完成clothes()方法staticProxy.clothes("XXXL");} }
-
-
- 动态代理:一个代理类代理多个目标类
-
在静态代理中,我们代理的仅仅是一个方法,但是在平时,一个类通常会有很多方法,对应的对象也会调用多个类,那么此时如果还是用静态代理,就会特别麻烦,所以就有了动态代理
-
JDK中提供了一个方法,可以动态的实现新增的接口,该方法是Proxy.newProxyInstance()
-
- 静态代理
- 基于CGLIB的动态代理
- cglib是第三方的工具库, 创建代理对象
- cglib的原理是继承, cglib通过继承目标类,创建它的子类,在子类中重写父类中同名的方法, 实现功能的修改
- 因为cglib是继承,重写方法,所以要求目标类不能是final的, 方法也不能是final的
- 不需要目标类有接口,通过继承就可以
- 经常用于框架中,例如Spring(SpringAOP)
- 基于JDK的动态代理
- 要求目标与代理类实现相同的接口,若目标类不存在接口,则无法使用该方式(要求有接口)
- 使用java反射包中的类和接口实现动态代理的功能
- 反射包 java.lang.reflect , 里面有三个类 : InvocationHandler , Method, Proxy
- InvocationHandler :接口(调用处理器),里面就一个方法invoke(),用来表示代理类用来干什么
- invoke:表示代理对象要执行的功能代码,即想要代理的功能
- 代理类完成的功能
- 调用目标方法,执行目标方法的功能
- 功能增强,在目标方法调用时,增加功能
- invoke方法原型
-
public Object invoke(Object proxy, Method method, Object[] args)
- 参数列表
-
Object proxy:jdk创建的代理对象,无需赋值
-
Method method:目标类中的方法,jdk提供method对象,无需赋值
-
Object[] args:目标类中的方法参数,jdk提供
-
- 使用:创建类实现InvocationHandler接口,重写invoke方法
-
- Method类:表示方法,确切的说就是目标类中的方法
- 作用:通过Method可以执行某个目标类的方法,Method.invoke() (注意,此处的invoke跟InvocationHandler中的invoke不同,这里的invoke是反射机制中的Method类中的方法,即method.invoke(Object,args))
- Proxy类:核心的对象,创建代理对象
-
之前创建对象都是new的方法,在动态代理中,使用Proxy的方法来创建
-
方法:newProxyInstance()
-
是一个静态方法,作用就是创建代理对象
-
方法原型
-
public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)
-
参数列表
-
ClassLoader loader:类加载器,向内存中加载对象,使用反射获取对象的classLoader
-
Class<?>[] interfaces:目标对象实现的接口(因为JDK的动态代理就是通过接口实现的),通过反射获取
-
InvocationHandler h:自己写的代理类要完成的功能(上述的InvocationHandler中的invoke)
-
返回值就是代理对象
-
-
-
-
- InvocationHandler :接口(调用处理器),里面就一个方法invoke(),用来表示代理类用来干什么
-
JDK动态代理的实现
-
创建接口,定义目标类要完成的功能
-
创建目标类实现接口
-
创建InvocationHandler接口的实现类,在invoke方法中完成代理类的功能
-
调用目标方法
-
增强功能
-
-
使用Proxy类的静态方法,创建代理对象,并把返回值转为接口类型
-
- 基于JDK的代理