CRISPY Web 服务,第 1 部分: 入门知识

本文讨论 Crispy。Crispy 的目标是为远程调用大量的传输提供单一入口点:如 RMI、EJB、JAX-RPC 或 XML-RPC。它的工作方式是使用属性来配置一个服务管理器,然后使用该管理器调用远程 API。

Sachin Mahajan, 软件开发, WSO2 Inc

Sachin MahajanSachin Mahajan 在软件开发方面(包括技术和管理职责)已有 9 年多的经验。目前在 IBM 的 SaaS 产品 LotusLive 的开发团队供职。



2010 年 1 月 18 日

引言

Crispy 是 Communication per Remote Invocation for different kinds of Services via ProxYs 的缩写。Crispy 是一个远程调用框架,它支持广泛的传输协议,如 RMI、EJB、JAX-RPC 和 XML-RPC。简而言之,Crispy 就像配置服务管理器(通过属性文件)来调用受支持的远程 API 一样容易。

对于初学者而言,下面列出的代码是配置 Crispy 的一个示例:

清单 1. 配置 Crispy 的示例代码
Properties prop = new Properties();
prop.put(Property.REMOTE_URL_AND_PORT, serviceUrl);
prop.put(Property.EXECUTOR_CLASS, typeOfExecutor);

ServiceManager manager = new ServiceManager(prop);
LibraryService library =  (LibraryService) manager.createService(LibraryService.class);
String author = library.findAuthor(myBook);
String isbn = library.findISBN(myBook);
…

在上面的代码中,我们创建了一个属性对象,并设置了远程 URL 和执行程序类型。执行程序的类型可以是 JAX RPC、JBoss Remoting、RMI 执行程序、XML RPC、REST 或 http 执行程序类型。在配置属性之后,可以创建 Crispy ServiceManager 的一个实例。现在可以使用 ServiceManager(工厂模式)创建远程服务对象(在本例中为 OrderService)。


背景知识

现在,我们已经对 Crispy 有了大致的了解,下面将提供一个示例,介绍没有 Crispy 的普通远程调用版本。

清单 2. Web 服务 (JAX-RPC)
public static final String LIBRARY_SERVICE_ENDPOINT = 
"http://myservicehost:9080/axis/services/LibraryService";
Service service = (Service) ServiceFactory.newInstance().createService(null);
Call call = service.createCall();
call.setTargetEndpointAddress("LIBRARY_SERVICE_ENDPOINT ");
call.setOperationName(new QName("findAuthor"));
QName paramXmlType = new QName(String.class.getName());
call.addParameter("arg0", paramXmlType, String.class, ParameterMode.IN);
call.setReturnType(new QName(String.class.getName()));
String result = (String) call.invoke(new String[] {”Alice in Wonderland”});
System.out.println("Author of Alice in Wonderland: " + result);

“call”对象用于调用 Web 服务。您可以自己输入也可以通过 WSDL 文档输入。我们将操作、参数和返回类型设置在 call 对象中,并“调用”Web 服务来获取所需的结果。

清单 3. XML-RPC (Apache XML-RPC)
XmlRpcClient client = new XmlRpcClient("http://myservicehost:9090");
Vector param = new Vector();
param.add(”Alice in Wonderland”);
String result = (String)
client.execute("crispysample.LibraryService.findAuthor", param);
System.out.println("Author of Alice in Wonderland: " + result);	
…

XmlRpcClient 是 XML-RPC 客户端的主要接入点。使用 execute 方法,可以使用传入的参数作为 param 对方法“calculateTip”执行请求。


使用 Crispy

上述代码仅显示了进行远程调用的两种方法,即通过 JAX-RPC 和 XML-RPC。可以用来进行远程调用的其他方法还有 RMI、EJB、REST、http 等。使用 Crispy,上述所有远程调用都可以使用配置的 ServiceManager 统一起来。可以使用 Properties 对象完成配置。

清单 4. JAX-RPC
MiniAxisServer server = new MiniAxisServer();
try {
	server.addService(LibraryService.class.getName(), 
    LibraryServiceImpl.class.getName());
	server.start();	
Properties properties = new Properties();
properties.put(Property.REMOTE_URL_AND_PORT, "LIBRARY_SERVICE_ENDPOINT");
properties.put(Property.EXECUTOR_CLASS, JaxRpcExecutor.class.getName());
} catch (Exception e) {
	e.printStackTrace();
}
finally {
	server.stop();
}
…
清单 5. XML-RPC
MiniXmlRpcServer server = new MiniXmlRpcServer();
try {

server.addService(LibraryService.class.getName(), LibraryServiceImpl.class.getName());
	server.start();
Properties properties = new Properties();
properties.put(Property.REMOTE_URL_AND_PORT, " http://myservicehost:9090");
properties.put(Property.EXECUTOR_CLASS, XmlRpcExecutor.class.getName());
} catch (Exception e) {
	e.printStackTrace();
}
finally {
	server.stop();
}
…

在配置 ServiceManager 之后,可以将其实例化,并且调用的远程方法如下所示:

清单 6. ServiceManager 示例
ServiceManager manager = new ServiceManager(properties);
Library library =  (LibraryService) manager.createService(LibraryService.class);
System.out.println("Author of Alice in Wonderland: " + result);

从上面的代码中,我们可以看到使用 Crispy 进行远程调用非常容易。服务管理器的配置非常方便;而且进行远程调用与进行本地调用类似。此外,客户端不需要知道有关其调用的远程技术的太多详情。


Crispy 实际操作

内部 Crispy

Crispy 框架包括三个组件:客户端或服务设计者、内部服务提供者和外部服务提供者。这三个组件都需要通信库,同时服务器组件只需要服务实现,而客户端需要服务接口。

图 1. Crispy(客户端服务器)组件(摘自:Crispy 文档)
Crispy(客户端服务器)组件

下面的图 2 描述了客户端与服务器组件之间的通信。如图所示,这是一个典型的客户端服务器通信。数据的内存表示形式(包括参数和结果)转换为适于传输到服务器的格式。这称为封送。在执行此方法之前在服务器上发生的反向处理称为取消封送。

图 2. Crispy 组件之间的通信(摘自:Crispy 文档)
Crispy 组件之间的通信

在客户端,ServiceManager 对象创建一个动态或静态代理,以便与服务器及代理对象中的调用方法通信。在将调用封送到服务器之前,调用一个可选调用来转换参数。如图 3 所示,此过程通过使用 net.sf.crispy.util.Converter.makeSimple 完成。在服务器收到请求时,将完成取消封送并使用 net.sf.crispy.util.Converter.makeComplex 返回转换的对象。

图 3. Crispy 中的对象转换(摘自:Crispy 文档)
Crispy 中的对象转换

如前所述,这是一个可选步骤,如果不想为转换对象实现 java.io.Serializable 接口,则可以调用此步骤。如上图所示,复杂的 Java 对象转换为 Java HashTable (java.util.HashTable) 对象,其中该项是 Java 对象的属性名,其值是属性值。它们之间的关系用 Java Vector 对象 (java.util.Vector) 进行映射。


用于同步或异步执行的 Crispy

为同步和异步执行,该框架主要用于客户端执行相应的调用。可以使用 MiniServer 对象 (net.sf.crispy.impl.MiniServer) 完成测试,假定已经启用了等效服务器。下面是设置执行性质(同步或异步)的方法示例。

清单 7. MiniServer 对象
MiniRmiServer server = new MiniRmiServer();
try {
		server.addService(LibraryServiceImpl.LOOKUP_NAME, 
        LibraryServiceImpl.class.getName());
	server.start();	
Properties properties = new Properties();
properties.put(Property.REMOTE_URL_AND_PORT, "rmi://localhost:1098");
prop.put(Property.DYNAMIC_PROXY_CLASS, Property.VALUE_FOR_CGLIB_DYNAMIC_PROXY);
properties.put(Property.EXECUTOR_CLASS, RmiExecutor.class.getName());
//Register the interface implementation mapping
prop.put(LibraryService.class.getName(), LibraryServiceImpl.class.getName());
ServiceManager manager = new ServiceManager(prop);
LibraryService library = manager.createService(LibraryService.class);
System.out.println("Author of Alice in Wonderland: " + 
        library.findAuthor(“Alice in Wonderland”));
} catch (Exception e) {
	e.printStackTrace();
}
finally {
		server.stop();
}
...

在上例中,缺省执行方式为同步。另一方面,对于异步执行而言,实现 AsynchronousCallback 对象 (net.sf.crispy.concurrent.AsynchronousCallback) 必须由 ServiceManager 对象注册。在本例中,LibraryService 对象使用注册的回调、异步执行的方法名和执行线程的最大大小创建。

清单 8. LibraryService 对象
Properties properties = new Properties();
properties.put(Property.REMOTE_URL_AND_PORT, "rmi://localhost:1098");
prop.put(Property.DYNAMIC_PROXY_CLASS, Property.VALUE_FOR_CGLIB_DYNAMIC_PROXY);
properties.put(Property.EXECUTOR_CLASS, RmiExecutor.class.getName());
//Register the interface implementation mapping
prop.put(LibraryService.class.getName(), LibraryServiceImpl.class.getName());
AsynchronousCallback callback = new AsynchronousCallbackForTests();
ServiceManager manager = new ServiceManager(prop);
 LibraryService library = manager.createService
(LibraryService.class,callback,new String[]{“findAuthor”},INT_MAX_NO_THREADS);
...

致谢

作者非常感谢 Crispy 框架的作者 Mario Linke,他在百忙之中抽出时间审阅了本文,并提出了宝贵意见。


总结

在本文中,除 Crispy 的内部工作外,我们还了解了 Crispy 在完成远程调用方面的便利性和易用性。我们还重点介绍了有关将 Crispy 用于同步和异步执行的一些详细信息,还介绍了通过 JAX-RPC 和 XML-RPC 进行的远程调用。这是有关 Crispy 的系列文章的第一篇(共两篇)。在下一篇中,我们将使用 Crispy 了解 RESTful 应用程序示例,同时使用其他框架扩展 Crispy。

参考资料

条评论

developerWorks: 登录

标有星(*)号的字段是必填字段。


需要一个 IBM ID?
忘记 IBM ID?


忘记密码?
更改您的密码

单击提交则表示您同意developerWorks 的条款和条件。 查看条款和条件

 


在您首次登录 developerWorks 时,会为您创建一份个人概要。您的个人概要中的信息(您的姓名、国家/地区,以及公司名称)是公开显示的,而且会随着您发布的任何内容一起显示,除非您选择隐藏您的公司名称。您可以随时更新您的 IBM 帐户。

所有提交的信息确保安全。

选择您的昵称



当您初次登录到 developerWorks 时,将会为您创建一份概要信息,您需要指定一个昵称。您的昵称将和您在 developerWorks 发布的内容显示在一起。

昵称长度在 3 至 31 个字符之间。 您的昵称在 developerWorks 社区中必须是唯一的,并且出于隐私保护的原因,不能是您的电子邮件地址。

标有星(*)号的字段是必填字段。

(昵称长度在 3 至 31 个字符之间)

单击提交则表示您同意developerWorks 的条款和条件。 查看条款和条件.

 


所有提交的信息确保安全。


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=10
Zone=SOA and web services
ArticleID=398408
ArticleTitle=CRISPY Web 服务,第 1 部分: 入门知识
publish-date=01182010