Hadoop阅读笔记(七)——代理模式

  关于Hadoop已经小记了六篇,《Hadoop实战》也已经翻完7章。仔细想想,这么好的一个框架,不能只是流于应用层面,跑跑数据排序、单表链接等,想得其精髓,还需深入内部。

  按照《Hadoop阅读笔记(五)——重返Hadoop目录结构》中介绍的hadoop目录结构,前面已经介绍了MapReduce的内部运行机制,今天准备入手Hadoop RPC,它是hadoop一种通信机制。

  RPCRemote Procedure Call Protocol)——远程过程调用协议,它是一种通过网络从远程计算机程序上请求服务,而不需要了解底层网络技术的协议。RPC协议假定某些传输协议的存在,如TCP或UDP,为通信程序之间携带信息数据。在OSI网络通信模型中,RPC跨越了传输层和应用层。RPC使得开发包括网络分布式多程序在内的应用程序更加容易。

  不同于其他RPC产品,Hadoop有属于自己RPC组件,依赖于《Hadoop阅读笔记(六)——洞悉Hadoop序列化机制Writable》中介绍的Hadoop Writable类型的支持。Hadoop Writable接口要求每个实现类都得确保将本类的对象正确序列化(writeObject)与反序列化(readObject)。因此,Hadoop RPC使用Java动态代理与反射实现对象调用方式,客户端到服务器数据的序列化与反序列化由Hadoop框架或用户自己来实现,也就是数据组装是定制的。

显然我们没法上来就直接剖析RPC,因为这里有一些绕不开的东西要先介绍:Writable序列化反序列化(已在第六篇介绍)、动态代理。所以,这里先介绍什么是动态代理。

  动态代理是代理模式的一种,还有一种就是静态代理。

  代理模式为其他对象提供一种代理,并以控制对这个对象的访问。而对一个对象进行访问控制的一个原因是为了只有在我们确实需要这个对象时才对它进行创建和初始化。它是给某一个对象提供一个替代者(占位者),使之在client对象和subject对象之间编码更有效率。代理可以提供延迟实例化(lazy instantiation),控制访问, 等等,包括只在调用中传递。

  静态代理:由程序员创建或特定工具自动生成源代码,再对其编译。在程序运行前,代理类的.class文件就已经存在了。 
  动态代理:在程序运行时,运用反射机制动态创建而成。

  1.静态代理

  Person.java(接口)

1 package hadoop.jackie.dao;
2
3 public interface Person {
4
5     public void eat();//人具有吃饭的行为
6
7     public void sleep();//人具有睡觉的行为
8
9 }

  

  PersonImpl.java(实现类,也就是这里的委托类)

 1 package hadoop.jackie.dao.impl;
 2
 3 import hadoop.jackie.dao.Person;
 4
 5 public class PersonImpl implements Person {
 6
 7     @Override
 8     public void eat() {
 9         System.out.println("我是吃货");
10
11     }
12
13     @Override
14     public void sleep() {
15         System.out.println("我是猪,别管我");
16
17     }
18
19 }

  PersonProxy.java(代理类)

 1 package hadoop.jackie.dao.impl;
 2
 3 import hadoop.jackie.dao.Person;
 4
 5 public class PersonProxy implements Person {
 6
 7     private PersonImpl personImpl;
 8
 9     public PersonProxy(PersonImpl personImpl){
10         this.personImpl = personImpl;
11     }
12
13     @Override
14     public void eat() {
15         System.out.println("吃饭前");
16         personImpl.eat();//调用委托类PersonImpl的吃饭方法
17         System.out.println("吃饭后");
18
19     }
20
21     @Override
22     public void sleep() {
23         System.out.println("睡觉前");
24         personImpl.sleep();//调用委托类PersonImpl的睡觉方法
25         System.out.println("睡觉后");
26
27     }
28
29 }

  PersonTest.java

 1 package hadoop.jackie.dao.test;
 2
 3 import hadoop.jackie.dao.impl.PersonImpl;
 4 import hadoop.jackie.dao.impl.PersonProxy;
 5
 6 public class PersonTest {
 7
 8     /**
 9      * @param args
10      */
11     public static void main(String[] args) {
12
13         PersonImpl personImpl = new PersonImpl();
14         PersonProxy personProxy = new PersonProxy(personImpl);
15         personProxy.eat();
16         personProxy.sleep();
17
18     }
19
20 }

  PersonTest.java运行结果为:

  从运行结果可以发现,类PersonProxy具备了PersonImpl的eat()和sleep()的方法,实现了对于类PersonImpl的委托。

  但是为什么称该模式为静态代理模式,从代码中可以发现,在代理类PersonProxy中需要手动配置委托类PersonImpl

  该模式效率较低,适用性较弱,代理类和委托类的耦合性较高。如果需要为多个委托类做代理,则会出现很多的代理类,从而有可能产生冗余代码。

  能够克服以上缺点的模式就是动态代理。

  2.动态代理

  介绍动态代理前,需要先了解相关的一个接口InvocationHandler和一个类Proxy

  (1)interface InvocationHandler

  该接口只有一个方法:Object invoke(Object proxy, Method method, Object[] args) 

  该方法用来处理方法的调用,实现类也有同样的意义;与代理类对象相关联则表示, 
  负责处理代理类应该有的动作,把所有的方法请求分发到invoke这个方法上。 (具体可以结合后面的代码理解)

  (2)class Proxy

  Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) 
  该方法用于产生代理对象,它与代理对象关联,当请求分发到代理对象后,会自动执行h.invoke(...)方法,

  Person.java(接口)

1 package hadoop.jackie.dynamic.dao;
2
3 public interface Person {
4
5     public void addGirlFriend();//小伙子具备找女朋友的方法
6
7 }

  PersonImpl.java(实现类,即委托类)

 1 package hadoop.jackie.dynamic.dao.impl;
 2
 3 import hadoop.jackie.dynamic.dao.Person;
 4
 5 public class PersonImpl implements Person {
 6
 7     @Override
 8     public void addGirlFriend() {
 9
10         System.out.println("吃饱睡好,该找个女盆友啦");
11
12     }
13
14 }

  PersonProxy.java(代理类)

 1 package hadoop.jackie.dynamic.dao.impl;
 2
 3 import java.lang.reflect.InvocationHandler;
 4 import java.lang.reflect.Method;
 5 import java.lang.reflect.Proxy;
 6
 7 public class PersonProxy implements InvocationHandler {
 8
 9     private Object targetGirl;
10
11     public Object bind(Object targetGirl){
12         this.targetGirl = targetGirl;
13         return Proxy.newProxyInstance(targetGirl.getClass().getClassLoader(), targetGirl.getClass().getInterfaces(), this);
14     }
15
16     @Override
17     public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
18         Object result = null;
19         System.out.println("找女盆友前");
20         result = method.invoke(targetGirl, args);
21         System.out.println("找女盆友后");
22         return result;
23     }
24
25 }

  PersonTest.java

 1 package hadoop.jackie.dynamic.dao;
 2
 3 import hadoop.jackie.dynamic.dao.impl.PersonImpl;
 4 import hadoop.jackie.dynamic.dao.impl.PersonProxy;
 5
 6 public class PersonTest {
 7
 8     /**
 9      * @param args
10      */
11     public static void main(String[] args) {
12         PersonProxy proxy = new PersonProxy();
13         Person personProxy = (Person)proxy.bind(new PersonImpl());
14         personProxy.addGirlFriend();
15
16     }
17
18 }

  运行结果为:

  通过以上两种模式的介绍以及展示的代码,需要注意一下几点:

  1.如何从生活场景理解代理模式?

  就这里的动态代理的代码逻辑来看:某小伙(Person.java)已经快奔三,急缺女友一枚(PersonImpl.java),但是由于种种原因如长得相貌出众、海拔太高、人品太好等,已经到了自己完全搞不定的时候了,而且这时家里催的又紧,怎么办?找代理啊,谁?媒婆啊(PersonProxy.java)。媒婆手头资源丰富,轻轻松松帮你搞定,还能按照你的需求进行定制比如瓜子壳脸还是猪腰子脸。这就是代理!

  2.动态代理中的invoke是什么鬼?

  在请求代理类的方法时,比如PersonTest.java:

personProxy.addGirlFriend();

  这个请求会被转到执行与代理类关联InvocationHandler 的invoke方法,然后通过

result = method.invoke(targetGirl, args);

  利用java的反射机制调用到方法addGirlFriend()。

  3.代理模式是无懈可击的?

  JDK的动态代理机制只能代理实现了接口的类,而不能实现接口的类就不能实现JDK的动态代理。

  在攻克hadoop源码中rpc模块的道路上,又前进了一个关卡,多走了几步^_^

   本文链接:《Hadoop阅读笔记(七)——代理模式

如果对你有帮助,欢迎点赞,对于Hadoop等大数据技术有兴趣的欢迎加群413471695交流讨论^_^。

时间: 2024-10-11 01:48:10

Hadoop阅读笔记(七)——代理模式的相关文章

Hadoop阅读笔记(一)——强大的MapReduce

前言:来园子已经有8个月了,当初入园凭着满腔热血和一脑门子冲动,给自己起了个响亮的旗号“大数据 小世界”,顿时有了种世界都是我的,世界都在我手中的赶脚.可是......时光飞逝,岁月如梭~~~随手一翻自己的博客,可视化已经快占据了半壁江山,思来想去,还是觉得把一直挂在嘴头,放在心头的大数据拿出来说说,哦不,是拿过来学学.入园前期写了有关Nutch和Solr的自己的一些阅读体会和一些尝试,挂着大数据的旗号做着爬虫的买卖.可是,时间在流失,对于大数据的憧憬从未改变,尤其是Hadoop一直让我魂牵梦绕

Hadoop阅读笔记(四)——一幅图看透MapReduce机制

时至今日,已然看到第十章,似乎越是焦躁什么时候能翻完这本圣经的时候也让自己变得更加浮躁,想想后面还有一半的行程没走,我觉得这样“有口无心”的学习方式是不奏效的,或者是收效甚微的.如果有幸能有大牛路过,请指教如何能以效率较高的方式学习Hadoop. 我已经记不清圣经<hadoop 实战2>在我手中停留了多久,但是每一页每一章的翻过去,还是在脑壳里留下了点什么. 一段时间以来,我还是通过这本书加深以及纠正了我对于MapReduce.HDFS乃至Hadoop的新的认识.本篇主要介绍MapReduce

Hadoop阅读笔记(三)——深入MapReduce排序和单表连接

继上篇了解了使用MapReduce计算平均数以及去重后,我们再来一探MapReduce在排序以及单表关联上的处理方法.在MapReduce系列的第一篇就有说过,MapReduce不仅是一种分布式的计算方法,更是一种解决问题的新思维.新思路.将原先看似可以一条龙似的处理一刀切成两端,一端是Map.一端是Reduce,Map负责分,Reduce负责合. 1.MapReduce排序 问题模型: 给出多个数据文件输入如: sortfile1.txt 11 13 15 17 19 21 23 25 27

Hadoop阅读笔记(六)——洞悉Hadoop序列化机制Writable

酒,是个好东西,前提要适量.今天参加了公司的年会,主题就是吃.喝.吹,除了那些天生话唠外,大部分人需要加点酒来作催化剂,让一个平时沉默寡言的码农也能成为一个喷子!在大家推杯换盏之际,难免一些画面浮现脑海,有郁闷抓狂的,有出成果喜极而涕的,有不知前途在哪儿的迷茫与不安……总的来说,近一年来,不白活,不虚度,感触良多,不是一言两语能说得清道的明的,有时间可以做个总结,下面还是言归正传谈技术吧. 上篇在了解了Hadoop的目录和源码结构后,说好的要啃源码的,那就得啃.也感谢一直以来关注我.支持我的网友

Hadoop阅读笔记(二)——利用MapReduce求平均数和去重

前言:圣诞节来了,我怎么能虚度光阴呢?!依稀记得,那一年,大家互赠贺卡,短短几行字,字字融化在心里:那一年,大家在水果市场,寻找那些最能代表自己心意的苹果香蕉梨,摸着冰冷的水果外皮,内心早已滚烫.这一年……我在博客园-_-#,希望用dt的代码燃烧脑细胞,温暖小心窝. 上篇<Hadoop阅读笔记(一)——强大的MapReduce>主要介绍了MapReduce的在大数据集上处理的优势以及运行机制,通过专利数据编写Demo加深了对于MapReduce中输入输出数据结构的细节理解.有了理论上的指导,仍

Hadoop阅读笔记(五)——重返Hadoop目录结构

常言道:男人是视觉动物.我觉得不完全对,我的理解是范围再扩大点,不管男人女人都是视觉动物.某些场合(比如面试.初次见面等),别人没有那么多的闲暇时间听你诉说过往以塑立一个关于你的完整模型.所以,第一眼,先走外貌协会的路线,打量一番,再通过望闻问切等各种手段获取关于你的大量信息(如谈吐.举止等),以快速建立起对于你的认识. 待人接物如此,搞技术也不例外,起码我是这样的.把玩了一番Hadoop的MapReduce过程,单词计数.去重.单表关联等运行的时候控制台打印出各种我看懂看不懂的信息,有了这些视

易学设计模式看书笔记(7) - 代理模式

代理模式 1.系统日志记录的例子:给系统中的业务逻辑加上日志 (1):最简单直接的做法 public class Test { private Logger logger = Loger.getLogger(this.getClass().getName()); public void doLgic(String name){ logger.log(name + "开始业务逻辑处理..."); //业务逻辑处理相关程序 System.out.println("业务逻辑处理相关

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

代理模式 为另一个对象提供一个替身或占位符以控制对这个对象的访问. 使用代理模式创建代表对象,让代表对象控制某个对象的访问,被代理的对象可以是远程的对象.创建开销大的对象或需要安全控制的对象. 在代理模式中的角色:  抽象对象角色(Subject):声明了目标对象和代理对象的共同接口,这样一来在任何可以使用目标对象的地方都可以使用代理对象. 目标对象角色(RealSubject):定义了代理对象所代表的目标对象. 代理对象角色(Proxy):代理对象内部含有目标对象的引用,从而可以在任何时候操作

《JavaScript设计模式与开发实践》读书笔记之代理模式

1.代理模式 代理模式是为一个对象提供一个代用品或占位符,以便控制对它的访问 1.1 一般的图片加载 var myImage=(function () { var imgNode=document.createElement('img'); document.body.appendChild(imgNode); return { setSrc: function (src) { imgNode.src=src; } } } )(); myImage.setSrc('http://xxx.com/