关于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(接口)

 package hadoop.jackie.dao;

 public interface Person {

     public void eat();//人具有吃饭的行为

     public void sleep();//人具有睡觉的行为

 }

  

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

 package hadoop.jackie.dao.impl;

 import hadoop.jackie.dao.Person;

 public class PersonImpl implements Person {

     @Override
public void eat() {
System.out.println("我是吃货"); } @Override
public void sleep() {
System.out.println("我是猪,别管我"); } }

  PersonProxy.java(代理类)

 package hadoop.jackie.dao.impl;

 import hadoop.jackie.dao.Person;

 public class PersonProxy implements Person {

     private PersonImpl personImpl;

     public PersonProxy(PersonImpl personImpl){
this.personImpl = personImpl;
} @Override
public void eat() {
System.out.println("吃饭前");
personImpl.eat();//调用委托类PersonImpl的吃饭方法
System.out.println("吃饭后"); } @Override
public void sleep() {
System.out.println("睡觉前");
personImpl.sleep();//调用委托类PersonImpl的睡觉方法
System.out.println("睡觉后"); } }

  PersonTest.java

 package hadoop.jackie.dao.test;

 import hadoop.jackie.dao.impl.PersonImpl;
import hadoop.jackie.dao.impl.PersonProxy; public class PersonTest { /**
* @param args
*/
public static void main(String[] args) { PersonImpl personImpl = new PersonImpl();
PersonProxy personProxy = new PersonProxy(personImpl);
personProxy.eat();
personProxy.sleep(); } }

  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(接口)

 package hadoop.jackie.dynamic.dao;

 public interface Person {

     public void addGirlFriend();//小伙子具备找女朋友的方法

 }

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

 package hadoop.jackie.dynamic.dao.impl;

 import hadoop.jackie.dynamic.dao.Person;

 public class PersonImpl implements Person {

     @Override
public void addGirlFriend() { System.out.println("吃饱睡好,该找个女盆友啦"); } }

  PersonProxy.java(代理类)

 package hadoop.jackie.dynamic.dao.impl;

 import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy; public class PersonProxy implements InvocationHandler { private Object targetGirl; public Object bind(Object targetGirl){
this.targetGirl = targetGirl;
return Proxy.newProxyInstance(targetGirl.getClass().getClassLoader(), targetGirl.getClass().getInterfaces(), this);
} @Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object result = null;
System.out.println("找女盆友前");
result = method.invoke(targetGirl, args);
System.out.println("找女盆友后");
return result;
} }

  PersonTest.java

 package hadoop.jackie.dynamic.dao;

 import hadoop.jackie.dynamic.dao.impl.PersonImpl;
import hadoop.jackie.dynamic.dao.impl.PersonProxy; public class PersonTest { /**
* @param args
*/
public static void main(String[] args) {
PersonProxy proxy = new PersonProxy();
Person personProxy = (Person)proxy.bind(new PersonImpl());
personProxy.addGirlFriend(); } }

  运行结果为:

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

  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交流讨论^_^。

友情赞助

如果你觉得博主的文章对你那么一点小帮助,恰巧你又有想打赏博主的小冲动,那么事不宜迟,赶紧扫一扫,小额地赞助下,攒个奶粉钱,也是让博主有动力继续努力,写出更好的文章^^。

    1. 支付宝                          2. 微信

                      

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

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

    前言:来园子已经有8个月了,当初入园凭着满腔热血和一脑门子冲动,给自己起了个响亮的旗号“大数据 小世界”,顿时有了种世界都是我的,世界都在我手中的赶脚.可是......时光飞逝,岁月如梭~~~随手一翻 ...

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

    酒,是个好东西,前提要适量.今天参加了公司的年会,主题就是吃.喝.吹,除了那些天生话唠外,大部分人需要加点酒来作催化剂,让一个平时沉默寡言的码农也能成为一个喷子!在大家推杯换盏之际,难免一些画面浮现脑 ...

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

    常言道:男人是视觉动物.我觉得不完全对,我的理解是范围再扩大点,不管男人女人都是视觉动物.某些场合(比如面试.初次见面等),别人没有那么多的闲暇时间听你诉说过往以塑立一个关于你的完整模型.所以,第一眼 ...

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

    时至今日,已然看到第十章,似乎越是焦躁什么时候能翻完这本圣经的时候也让自己变得更加浮躁,想想后面还有一半的行程没走,我觉得这样“有口无心”的学习方式是不奏效的,或者是收效甚微的.如果有幸能有大牛路过, ...

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

    继上篇了解了使用MapReduce计算平均数以及去重后,我们再来一探MapReduce在排序以及单表关联上的处理方法.在MapReduce系列的第一篇就有说过,MapReduce不仅是一种分布式的计算 ...

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

    前言:圣诞节来了,我怎么能虚度光阴呢?!依稀记得,那一年,大家互赠贺卡,短短几行字,字字融化在心里:那一年,大家在水果市场,寻找那些最能代表自己心意的苹果香蕉梨,摸着冰冷的水果外皮,内心早已滚烫.这一 ...

  7. 结构型模式(七) 代理模式(Proxy)

    一.动机(Motivate) 在面向对象系统中,有些对象由于某种原因(比如对象创建的开销很大,或者某些操作需要安全控制,或者需要进程外的访问等),直接访问会给使用者.或者系统结构带来很多麻烦.如何在不 ...

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

    1.代理模式 代理模式是为一个对象提供一个代用品或占位符,以便控制对它的访问 1.1 一般的图片加载 var myImage=(function () { var imgNode=document.c ...

  9. Java并发编程阅读笔记-Java监视器模式示例

    1.前言 书中在解释Java监视器模式的时候使用了一个车辆追踪器例子,根据不同的使用场景给出了不同的实现和优化. 2.监视器模式示例 实现一个调度车辆的"车辆追踪器",每台车使用一 ...

随机推荐

  1. 书TO BE READED

    Books Created Wednesday 10 August 2011 1.<你的降落伞是什么颜色> 在求职书里面,我觉得这本书是最接近于圣经的. 第一版出现大概还是上世纪70年代末 ...

  2. 解剖SQLSERVER 完结篇 关于Internals Viewer源代码

    解剖SQLSERVER 完结篇 关于Internals Viewer源代码 大家可能都用过Internals Viewer这个软件 <查看SQLSERVER内部数据页面的小插件Internals ...

  3. 在Ubuntu13.04中配置Jexus+Mono3.2运行Asp.Net Mvc 4站点 (二)

    开始写这篇前看了看日期,写下这个序列的前一半竟是两个月前的事情了,无比惭愧.这段时间尝试重新组织Mvc4的项目引用,创建了两个项目模板,一个是简单模式,即仅包含Mvc基本功能.另一个是包含了Mvc4 ...

  4. [后端人员耍前端系列]AngularJs篇:30分钟快速掌握AngularJs

    一.前言 对于前端系列,自然少不了AngularJs的介绍了.在前面文章中,我们介绍了如何使用KnockoutJs来打造一个单页面程序,后面一篇文章将介绍如何使用AngularJs的开发一个单页面应用 ...

  5. Nginx + CGI/FastCGI + C/Cpp

    接着上篇<Nginx安装与使用>,本篇介绍CGI/FASTCGI的原理.及如何使用C/C++编写简单的CGI/FastCGI,最后将CGI/FASTCGI部署到nginx.内容大纲如下: ...

  6. 【译】用Fragment解决屏幕旋转(状态发生变化)状态不能保持的问题

    这篇文章解决了在StackOverflow上一个经常被提到的问题. 在配置发生变化(Configuration changs)时,什么是最好的保存活动对象方法,比如运行中的线程,Sockets,Asy ...

  7. Unity3D音乐音效研究-MIDI与波表

    其实音乐音效这个命题本身没什么好研究的. Unity3D提供了丰富的结构和使用方式,足够使用了. 但是我有一些小小的想法和需求,一般的Unity资料并没有给我答案. 一个是容量要小.MP3.OGG的高 ...

  8. ASP.NET中一种超简单的Ajax解决方案

    为什么是Ajax2? 因为之前有一个blqw.Ajax,并且已经在项目中投入使用了,但是没有这个方便,这个是后来才弄的,为了纪念第一版的blqw.Ajax,所以这个就2了... 话说看了评论才发现,原 ...

  9. Spring Trasnaction管理(3)- 事务嵌套

    问题导读 Spring 如何管理嵌套的事务 Spring事务传播机制 Nested 和 RequireNew 有何区别 事务传播机制 事务的传播机制应该都比较熟悉 在日常开发中会遇到需要事务嵌套的情况 ...

  10. Java-条件语句、循环语句练习

    题目一:一张纸的厚度大约是0.08mm,对折多少次之后能达到珠穆朗玛峰的高度(8848.13米)? double height=0.08; for(int i=1;i>0;i++) { heig ...