本文出自   http://blog.csdn.net/shuangde800



本笔记内容:
1. JAVA远程代理调用(RMI)
2. 代理模式


走进代理模式

在上一篇的状态模式中,我们实现了一个糖果机GumballMachine,  客户通过投币可以买到糖果.

现在设想这样一种情况: 糖果机是属于某个糖果公司的,这个公司的CEO坐在办公室里喝茶,看报纸, 但他还想要随时了解糖果机的状态,

比如还剩下多少个糖果,卖了多少钱等等. CEO要怎样才能远程"遥控"糖果机获取信息呢?

这就得用到代理模式(Proxy Pattern)了.

可能我们会想到通过socket网络连接, 自己定义好协议去控制糖果机.这个其实就是代理模式的底层实现.

所谓代理(Proxy)就是代表某个真实的对象, 这个"代理"可以看作是真正的对象, 比如CEO在办公室中拿到了糖果机的"代理", 然后CEO

对"代理"进行的任何操作,到会"传送"到远程真实的糖果机上, 然后糖果机就会作出反应, 看起来好像"代理"就是真正的糖果机一样.

这一切的动作是利用网络和真正对象沟通的.

远程代理的角色

远程代理就好比"远程对象的本地代表".

何谓"远程对象"? 这是一种对象,活在不同的Java虚拟机(JVM)堆中(更一般的说法,在不同的地址空间运行的远程对象).

何谓"本地代表"? 这是一种可以由本地方法调用的对象,其行为会转发到远程对象中.

你的客户对象所做的就像是在做远程方法调用, 但其实只是调用本地堆中的"代理对象"上的方法,

再由代理处理所有网络通信的底层细节

JAVA远程方法调用(RMI)

如果要自己手动去实现网络通信的底层, 那么显然会大大加大编程复杂度, 幸运的是, Java中已经有内置工具给我们使用了.

这就是: Java远程方法调用(RMI: Remote Mehod Invocation)

用Java RMI创建远程服务的基本步骤:

1. 创建远程接口

// 这个接口扩展自Remote,支持远程调用
public interface MyRemote extends Remote{
// 每次远程调用都是“有风险的”,因为会设计网络和I/O
// 所以这个接口的方法都要声明异常
// 还要确定方法的返回值是primitive类型或者可序列化(Serializable)类型
// 远程方法的变量会被打包并通过网络运送,这要靠序列化来完成
// 自定义的类必须序列化
public String sayHello() throws RemoteException;
}

2. 实现远程接口

public class MyRemoteImpl extends UnicastRemoteObject implements MyRemote{

      // 声明默认构造器
protected MyRemoteImpl() throws RemoteException {
super();
} // 实现接口
public String sayHello() throws RemoteException {
return "Hello, world!";
} public static void main(String[] args) { try {
MyRemote service = new MyRemoteImpl();
// 用Naming.rebind()绑定到remiregistry
Naming.rebind("rmi://127.0.0.1/RemoteHello", service);
} catch (Exception e){
e.printStackTrace();
}
}
}

3. 命令行编译上面两个类(PS. 用的是Ubuntu系统,不是用IDE写的,所以两个类也没有package,放在同一个目录下。实际上,如果直接用IDE编译会遇到一个问题,后面会提)

这样就把Remote.java 和RemoteImpl.java两个类都编译了,编译完后,产生两个编译文件:

MyRemote.class和MyRemoteImpl.java

4. 用rmic产生stub和skeleton

rmic是JDK内的一个工具,用来为一个服务类产生stub和skeleton。命名习惯是在远程实现的名字后面加上_Stub或_Skel。rmic有一些选项可以调整,包括不要产生skeleton,查看源代码,甚至使用IIOP作为协议。这个例子使用的是rmic常见的方式,将类产生在当前目录下(就是cd到的目录)。注意,rmic必须看到你的实现类,所以你可能会从你的远程实现所在的目录下执行rmic

执行完之后,发现目录下多了一个名为MyRemote_Stub.class的文件:

5. 执行rmiregistry

开启一个终端,启动rmiregistry

注意这个终端不要关闭!

6. 启动服务端服务

开启另一个终端,启动服务

这个终端也不要关闭。

---------------------------分割线------------------------------

上面是服务端的代码,下面来实现客户端的代码。

客户必须取得stub对象(我们的代理)以调用其中的方法。所以我们就需要RMI Registry的帮忙。客户从Registry中寻找(lookup)代理,就好像在电话簿里寻找一样,说:“我要找这个名字的stub”.

import java.rmi.*;

public class MyRemoteClient {
public static void main (String[] args) {
new MyRemoteClient().go();
} public void go() { try{
// 返回值是Object,所以要转换类型
// 需要ip地址或主机名,以及服务器绑定/重绑定时用的名称
MyRemote service = (MyRemote)Naming.lookup("rmi://127.0.0.1/RemoteHello"); // 看起来和一般的方法调用没有区别!(除了必须注意RemoteException之外)
String s = service.sayHello(); System.out.println(s); } catch (Exception e) {
e.printStackTrace();
}
}
}

编译,并且运行,发现输出“Hello world!”了!

OK !这就是RMI的基本过程了,当然实际应用中肯定还会有些变化的。

对于RMI, 程序员常犯的三个错误:

1. 忘了在启动远程服务之前先启动rmiregistry(要用Naming.rebind()注册服务, rmiregistry必须是运行的)

2. 忘了让变量和返回值的类型成为可序列化的类型(这种错误无法在编译期发现, 只会在运行时发现)

3. 忘了给客户提供stub类.

在敲上面的例子时, 我用IDE(Eclipse)来写过,但是步骤3编译时,遇到的问题:

java.rmi.ConnectException: Connection refused to host: 127.0.0.1

我试了其它电脑,还换了系统实现上述代码, 编译时都遇到了这个问题。

有没有人知道告诉我一下?

定义代理模式

代理模式为另一个对象提供一个替身或占位符以控制这个对象的访问

  • Subject, 为RealSubject和Proxy提供了接口, 通过实现同一个接口, Proxy在RealSubject出现的地方取代它
  • RealSubject是真正做事的对象,它是被proxy代理和控制访问的对象.
  • Proxy持有RealSubject的引用.在某些例子中, Proxy还会负责RealSubject对象的创建与销毁.客户和RealSubject的交互都必须通过Proxy.因为Proxy和RealSbuject实现相同的接口(Subject),所以任何用到RealSubject的地方,都可以用Proxy取代.Proxy也控制了对RealSubject的访问,在某些情况下,我们可能需要这样的控制.这些情况包括RealSubject是远程的对象, RealSubject创建开销大, 或RealSubject需要被保护.

代理模式的其他玩法

远程代理是一般代理模式的一种实现, 但是代理了模式的变体相当多

比如: 虚拟代理, 缓存代理,同步代理, 防火墙代理和写入时复制代理.

限于篇幅, 下次再继续学习

【设计模式】学习笔记15:代理模式(Proxy Pattern)的更多相关文章

  1. 设计模式系列之代理模式(Proxy Pattern)——对象的间接访问

    说明:设计模式系列文章是读刘伟所著<设计模式的艺术之道(软件开发人员内功修炼之道)>一书的阅读笔记.个人感觉这本书讲的不错,有兴趣推荐读一读.详细内容也可以看看此书作者的博客https:/ ...

  2. 乐在其中设计模式(C#) - 代理模式(Proxy Pattern)

    原文:乐在其中设计模式(C#) - 代理模式(Proxy Pattern) [索引页][源码下载] 乐在其中设计模式(C#) - 代理模式(Proxy Pattern) 作者:webabcd 介绍 为 ...

  3. 二十四种设计模式:代理模式(Proxy Pattern)

    代理模式(Proxy Pattern) 介绍为其他对象提供一个代理以控制对这个对象的访问. 示例有一个Message实体类,某对象对它的操作有Insert()和Get()方法,用一个代理来控制对这个对 ...

  4. 设计模式 - 代理模式(proxy pattern) 未使用代理模式 具体解释

    代理模式(proxy pattern) 未使用代理模式 详细解释 本文地址: http://blog.csdn.net/caroline_wendy 部分代码參考: http://blog.csdn. ...

  5. 代理模式(Proxy pattern)

    代理模式(proxy pattern):作用:为其他对象提供一种代理,以控制对这个对象的访问.代理对象在客户端对象和目标对象之间起中介的作用. 代理模式涉及到的角色: 抽象角色:声明真实对象和代理对象 ...

  6. 【转】设计模式(十一)代理模式Proxy(结构型)

    设计模式(十一)代理模式Proxy(结构型) 1.概述 因为某个对象消耗太多资源,而且你的代码并不是每个逻辑路径都需要此对象, 你曾有过延迟创建对象的想法吗 ( if和else就是不同的两条逻辑路径) ...

  7. 设计模式——代理模式(Proxy Pattern)

    代理模式(Proxy),为其他对象提供一种代理以控制对这个对象的访问. UML图: 模型设计: Subject类: package com.cnblog.clarck; /** * Subject 类 ...

  8. 设计模式学习笔记--备忘录(Mamento)模式

    写在模式学习之前 什么是设计模式:在我们进行程序设计时,逐渐形成了一些典型问题和问题的解决方式,这就是软件模式:每个模式描写叙述了一个在我们程序设计中常常发生的问题,以及该问题的解决方式:当我们碰到模 ...

  9. 13.代理模式(Proxy Pattern)

    using System; namespace Test { //抽象角色:声明真实对象和代理对象的共同接口. //代理角色:代理对象角色内部含有对真实对象的引用,从而可以操作真实对象, //同时代理 ...

  10. c#设计模式之代理模式(Proxy Pattern)

    引言 代理这个词语,大家在现实世界已经频繁的接触过,例如火车站代理售票点,因为这些代理售票点的存在,我们不必要去火车站的售票处就可以查询或者取到火车票.代理点本身是没有能力生产车票的,我们在代理处享受 ...

随机推荐

  1. 【NOIP2014】联合权值 树上dp

    题目描述 Description 无向连通图G 有n 个点,n - 1 条边.点从1 到n 依次编号,编号为 i 的点的权值为W i   ,每条边的长度均为1 .图上两点( u ,  v ) 的距离定 ...

  2. POJ 1654 Area 计算几何

    #include<stdio.h> #include<string.h> #include<iostream> #include<math.h> usi ...

  3. 对于asp.net mvc异步查询

    如何做MVC异步查询,做列表页面. 查询是项目中必不可少的工作,而且不同的项目不同的团队,都有自己的简单方法.Asp.net mvc 有自己独特的优势,下面是结合mvc实现一个产品列表的Demo. 问 ...

  4. Accessing an element's parent with ElementTree(转)

    Today I ran across a situation where I needed to programmatically remove specific elements from a KM ...

  5. hadoop学习;Streaming,aggregate;combiner

    hadoop streaming同意我们使用不论什么可运行脚本来处理按行组织的数据流,数据取自UNIX的标准输入STDIN,并输出到STDOUT 我们能够用 linux命令管道查看文本有多少行,cat ...

  6. make mrproper and make clean

    make mrproper命令会删除所有的编译生成文件.内核配置文件(.config文件)和各种备份文件,所以几乎只在第一次执行内核编译前才用这条命令. make clean命令则是用于删除大多数的编 ...

  7. windows tomcat nginx session(当一台tomcat关闭后)

    在windows下作nginx负载均衡测试. nginx的配置文件如下: worker_processes  1; events { worker_connections  1024; } http ...

  8. MyBatis的动态SQL详解-各种标签使用

    MyBatis的动态SQL是基于OGNL表达式的,它可以帮助我们方便的在SQL语句中实现某些逻辑. MyBatis中用于实现动态SQL的元素主要有: if choose(when,otherwise) ...

  9. dao层的泛型实现(2种方法)

    一: package com.wzs.test2.dao; import java.util.List; public interface CommonDAO { public <T> v ...

  10. Android Binder 设计与实现 - 设计篇

    关键词 Binder Android IPC Linux 内核 驱动 摘要 Binder是Android系统进程间通信(IPC)方式之一.Linux已经拥有管道,system V IPC,socket ...