学习笔记-设计模式之代理模式

本文内容源于视频教程,若有侵权,请联系作者删除。

一、概念

代理模式(Porxy Pattern)是指为其他对象提供一种代理,以控制对这个对象的访问。

简言之:房产中介,售票黄牛都属于代理。

二、实现

1.静态代理

需求:实现父亲替儿子找对象。

 首先构造一个儿子,并且具有找对象的方法。

1 public class Son {
2 
3     public void findLove(){
4         System.out.println("儿子找对象,要求肤白貌美,大长腿");
5     }
6 }

构造一个帮儿子找对象的父亲,在找对象之前需要筛选,找到后需要安排后续事情。

 1 public class Father {
 2 
 3     private Son son;
 4 
 5     public Father(Son son) {
 6         this.son = son;
 7     }
 8 
 9     public void findLove(){
10         System.out.println("父亲帮儿子筛选对象");
11         this.son.findLove();
12         System.out.println("准备婚礼。。");
13     }
14 }

测试类如下。

1 public class StaticProxyTest {
2 
3     public static void main(String[] args) {
4         Father father = new Father(new Son());
5         father.findLove();
6     }
7 }

运行结果

父亲帮儿子筛选对象
肤白貌美,大长腿
准备婚礼。。

虽然是父亲帮儿子找对象,但是最终调用的还是儿子的findLove方法。这就是代理模式。

从代码中也能看出,父亲在找对象前会帮儿子筛选对象,找到后会帮忙婚礼。在到了方法增强的效果的同时,没有改变原来的方法。可见代理模式遵循了开闭原则。

以上的缺点也很明显,父亲只能帮儿子找对象,不能给其他人找对象,极大限制了应用范围。随着时代发展,找对象的需求越来越多,由此衍生出了一种职业——媒婆。

媒婆可以给任何人找对象,在物色对象时会筛选符合要求的青年,在找对象之后会准备婚礼。下面通过两种动态代理实现。

2.动态代理

2.1 jdk动态代理

首先创建接口Person,所有实现此接口的类都可以找对象。

1 public interface Person {
2     
3     void findLove();
4     
5 }

接着创建一个女儿,实现person并且具有找对象方法。

1 public class Girl implements Person {
2     
3     @Override
4     public void findLove() {
5         System.out.println("女儿找对象:高富帅");
6     }
7 }

然后创建媒婆,能帮所有人找对象,并且找对象前和找对象后都有相应工作。

 1 public class JdkMeiPo implements InvocationHandler {
 2 
 3     private Person person;
 4 
 5     public Person getInstance(Person person) {
 6         this.person = person;
 7         Class<? extends Person> clazz = person.getClass();
 8         return (Person) Proxy.newProxyInstance(clazz.getClassLoader(), clazz.getInterfaces(), this);
 9      }
10 
11     @Override
12     public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
13         before();
14         Object invoke = method.invoke(this.person, args);
15         after();
16         return invoke;
17     }
18 
19     private void before(){
20         System.out.println("找对象前筛选对象");
21     }
22 
23     private void after(){
24         System.out.println("找对象后举办婚礼");
25     }
26 }

测试类

1 public class JdkProxyTest {
2 
3     public static void main(String[] args) {
4         Person person = new JdkMeiPo().getInstance(new Girl());
5         person.findLove();
6     }
7 }

执行结果

找对象前筛选对象
女儿找对象:高富帅
找对象后举办婚礼

这里的媒婆不仅能给女儿找对象,只要是继承了Person的类都可以找。

jdk代理的核心是实现InvocationHandler类并实现了其invoke方法,媒婆类中的getInstance方法返回的实际上是girl的一个代理对象,这个对象由jdk生成,该对象的findLove方法不仅有Girl的findLove方法,同时也有媒婆类中的before和after方法。

jdk动态代理实现原理:

1.拿到被代理类的引用,并且获取它的所有接口

2.JDK Proxy类重新生成一个类,实现了被代理类的所有方法

3.动态生成java代码,把增强逻辑加入到新生成的代码中

4.编译新生成的类

5.加载并运行

2.2 Cglib动态代理

在上面的基础上,写一个cglib的媒婆类

 1 public class CglibMeiPo implements MethodInterceptor {
 2 
 3     public Object getInstance(Class<?> clazz){
 4         Enhancer enhancer = new Enhancer();
 5         enhancer.setSuperclass(clazz);
 6         enhancer.setCallback(this);
 7         return enhancer.create();
 8     }
 9 
10     @Override
11     public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
12         before();
13         Object invoke = methodProxy.invokeSuper(o, objects);
14         after();
15         return invoke;
16     }
17 
18     private void before(){
19         System.out.println("找对象前筛选对象");
20     }
21 
22     private void after(){
23         System.out.println("找对象后举办婚礼");
24     }
25 }

测试类:

1 public class CglibProxyTest {
2 
3     public static void main(String[] args) {
4         Son instance = (Son)new CglibMeiPo().getInstance(Son.class);
5         instance.findLove();
6     }
7 }

输出结果

找对象前筛选对象
肤白貌美,大长腿
找对象后举办婚礼

与Jdk动态代理一样,Cglib同样动态生成了一个代理类,不同的是Jdk通过实现接口的方式生成,Cglib通过继承目标类实现。

2.3.CGLib 和 JDK 动态代理对比

1.JDK 动态代理是实现了被代理对象的接口,CGLib 是继承了被代理对象。
2.JDK 和 CGLib 都是在运行期生成字节码,JDK 是直接写 Class 字节码,CGLib 使用 ASM框架写 Class 字节码,Cglib 代理实现更复杂,生成代理类比 JDK 效率低。
3.JDK 调用代理方法,是通过反射机制调用,CGLib 是通过 FastClass 机制直接调用方法,CGLib 执行效率更高。

posted @ 2020-07-22 23:03  落雨有清·风  阅读(135)  评论(0编辑  收藏  举报