
设计模式之代理模式 原创
春节不停更,此文正在参加「星光计划-春节更帖活动」
日积月累,水滴石穿 😄
什么是代理模式
代理模式,给某对象提供一个代理对象,并由代理对象控制对原对象的引用。讲的直白一点,就是找个人来帮我干原本由我来干的事情,而且找来的这个人干的可能比我还好。
代理模式的组成
-
抽象角色:通过接口或抽象类声明真实角色需要实现的业务方法。也就是要干的事情,比如结婚、找房。
-
代理角色:实现抽象角色,是真实角色的代理,通过真实角色的业务逻辑方法来实现抽象方法,并可以附加自己的操作。也就是找过来的人,比如婚庆公司、房产中介。
-
真实角色:实现抽象角色,定义真实角色所要实现的业务逻辑,供代理角色调用。真实角色也就是我,我要结婚、我要找房。
代理模式的好处
- 功能增强
- 保护目标对象
- 一定程度上降低了系统的耦合度
实现代理模式的方式
- 静态代理:由我们程序员创建一个 Java 类,作为代理类。需要代理的真实对象是已经确认了的。
- 动态代理
- JDK动态代理:利用反射机制动态地生成代理对象。要求目标类与代理类实现相同的接口,若目标类没有实现接口,则无法使用 JDK 动态代理。
- Cglib动态代理:
Cglib
既可代理接口又可以代理类。通过继承目标类,生成子类。在生成的子类中重写父类的方法,也就是重写目标类的方法,实现对其功能的增强。既然是继承,那就要求目标类不能是final
的,方法也不能是final
的。
静态代理
就拿结婚来举例吧!
- 结婚 属于抽象角色,也就是要干的事情。
- 婚庆公司属于代理角色,帮忙布置婚礼现场、录制、主持婚礼。
- 结婚人,属于真实角色。结婚人就想结婚然后洞房而已,为什么还要额外做这么多事呢,所以就找一家婚庆公司。
实例
- 提供抽象角色,里面有业务方法 marry。
- 代理角色,实现抽象角色。
- 真实角色,也实现抽象角色。
- 测试
你在准备选择婚庆公司的时候,发现了一家更好的婚庆公司 B,婚庆公司 B 正好在搞周年庆,价格便宜,套餐选项更多,你就选择了 婚庆公司 B 主办你的婚礼。
增加代理类
- 测试
优缺点
优点
-
简单,便于理解
-
符合开闭原则的情况下对目标对象进行功能扩展。
缺点
- 需要为每一个目标对象都创建一个或多个代理类,增加了维护成本以及开发成本。
- 抽象角色有所改动会影响到代理角色。
动态代理
JDK代理
使用 JDK 动态代理就不需要手动创建代理类,利用反射机制动态地生成代理对象。要求目标类与代理类实现相同的接口,若目标类没有实现接口,则无法使用 JDK 动态代理。
小杰还是使用结婚来举例吧!进行改造。
- MarryProxy
创建类 MarryProxy
并实现InvocationHandler
接口。
- 测试类
可以发现代理类对象由反射进行产生,并不需要再由程序员手动进行创建了。
在上面我们需要注意几个方法。小杰分别介绍一下:
- newProxyInstance
newProxyInstance
方法属于Proxy
类的静态方法,Proxy
类位于 java.lang.reflect
包,该方法有三个参数,含义分别如下:
- loader:类加载器,将类加载到 JVM 中。可以使用反射得到,比如:
MarryPerson.class.getClassLoader()
- interfaces:目标类实现的接口,可以传入多个。可以通过反射获取,比如:
MarryPerson.class.getInterfaces()
或者new Class[]{Marry.class}
。这里一定传入接口哦!否则会出Xxx is not an interface
异常。 - h:代理类需要完成的逻辑。
newProxyInstance
方法返回值为:返回代理对象。
- invoke
InvocationHandler
接口位于java.lang.reflect
包中,接口中就一个 invoke
方法,该方法有三个参数,含义分别如下:
- proxy:JDK 动态创建的代理对象。
- method:代理类执行的方法。
- args:需要传给方法的参数。
invoke
方法返回值的含义为:目标方法的返回值。
JDK动态代理
的要求还是挺严格的,必须基于接口创建代理类。如果我就是不想写接口怎么办,有什么方式可以产生代理类吗?那这时候就需要使用 Cglib
动态代理方式了,接下来小杰就来介绍介绍它。
Cglib代理
Cglib
是第三方工具库,Cglib
既可代理接口又可以代理类。通过继承目标类,生成子类。在生成的子类中重写父类的方法,也就是重写目标类的方法,实现对其功能的增强。既然是继承,那就要求目标类不能是 final
的,方法也不能是final
的,如果是 final
那也没办法进行继承。
- 需要加入第三方依赖:
- 创建
MarryCglibProxy
类并继承MethodInterceptor
代理接口
- 源码
代理实现类
-
源码
Cglib代理
和 JDK 代理
是很相似的,都要实现代理器接口完成。还是需要注意几个方法。小杰分别介绍一下:
- create
create
方法属于Enhancer
类的静态方法,Enhancer
类位于 net.sf.cglib.proxy
包,该方法有两个参数,含义分别如下:
- type:指定目标类的类型。可以传入接口或者类,如果传入的是接口,代理类的源码是实现了该接口和
Factory
接口,如果传入的是类,源码是继承了类并实现了Factory
接口。 - callback:回调,意思是我们提供一个方法,它会在合适的时候调用我们提供的方法。
Callback
是一个接口,并不包含方法的声明,我们通常使用它的子接口MethodInterceptor
。
create
方法返回值的为:返回代理对象。
- MethodInterceptor
可以发现该方法的参数跟 JDK动态代理
的参数差不多,就是多了一个参数 methodProxy
,其余参数的意义是一致的。
- methodProxy:方法代理,不需要过于关心。
其实不论是使用 JDK动态代理
实现 InvocationHandler
还是使用Cglib动态代理
实现MethodInterceptor
,我们都只需要关心 method
与args
两个参数。
