IBM®
跳转到主要内容
    中国 [选择]    使用条款
 
 
Select a scope: Search for:    
    首页    产品    服务与解决方案     支持与下载    个性化服务    
跳转到主要内容

developerWorks 中国  >  SOA and Web services  >

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

developerWorks
文档选项

未显示需要 JavaScript 的文档选项

英文原文

英文原文


级别: 中级

Sachin Mahajan, 软件开发, IBM

2009 年 10 月 27 日

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

引言

Crispy 代表通过代理为不同类型的服务提供远程调用通信。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。



参考资料



关于作者

Sachin Mahajan

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




对本文的评价










回页首


IBM 公司保留在 developerWorks 网站上发表的内容的著作权。未经IBM公司或原始作者的书面明确许可,请勿转载。如果您希望转载,请通过 提交转载请求表单 联系我们的编辑团队。
    关于 IBM 隐私条约 联系 IBM 使用条款