客户端基本模型
本节阐述了如何从SCA组件和非SCA组件访问SCA服务,以及如何调用服务的方法。
从组件实现访问服务
以下的小节描述了获取服务的两种方式:
- 使用引用注入
- 使用模块上下文
引用注入是推荐的方式,因为这将让代码中的API调用最小。另一种方法一般只在引用注入不可用的情况下使用
使用引用注入
通过引用注入获取服务的方法,是通过以一个服务接口定义和一个@Reference 标签标注一个Java类的字段。
@Reference标签拥有以下属性:
- name – 引用的名称,默认是Java类属性的名字
- required – 服务注入或服务是否是必须的
以下代码使用@Reference标签定义Java实现中的服务引用定义的例子。引用的名字为 “helloService”,引用的类型为HelloService。clientMethod() 调用了helloService引用的服务上的”hello”操作。
package services.client; import services.hello.HelloService; import org.osoa.sca.annotations.*; @Service(ClientService.class) public class ClientServiceImpl implements ClientService { @Reference(name="helloService", required=true) private HelloService helloService; public void clientMethod() { String result = helloService.hello("Hello World!"); … } } |
<?xml version="1.0" encoding="ASCII"?> |
如果引用是一个数组或是java.util.Collection, 则默认组件类型的multiplicity属性根据@Reference 的required属性为true还是false分别是为1..n 或 0..n。
以下代码为在Java实现中使用标签@Reference标注类型java.util.List的属性为一个服务应用的定义的例子。该服务引用的名字是”helloServices”,类型为HelloService。方法clientMethod() 调用了该服务引用所引用的所有的服务的”hello”操作。在这个例子中,至少要有一个HelloService存在, 所以 required 属性为 true。
package services.client; import java.util.List; import org.osoa.sca.annotations.*; import services.hello.HelloService; @Service(ClientService.class) public class ClientServiceImpl implements ClientService { @Reference(name="helloService", required=true) private List helloServices; public void clientMethod() { … HelloService helloService = (HelloService)helloServices.get(index); String result = helloService.hello("Hello World!"); … } } |
以下代码为上述构件实现的构件类型定义。组件的类型不需要在这里指明,因为可以通过Java类反射信息得到。
<?xml version="1.0" encoding="ASCII"?> |
如果一个组件需要访问的服务只有在运行时才能知道它的名字,那么该服务只能从ModuleContext中获得。
为了使用模块上下文访问一个服务,那么我们需要做两件事情:
- 1. 必须定义一个字段,用以注入模块上下文。
- 2. 必须调用注入的模块上下文的一个方法。
模块上下文的注入是通过添加一个类型为ModuleContext 字段并以@Context
标签加以标注。被注入的上下文的类型是由字段的类型决定的;在这里,即是ModuleContext。
以下代码为Java接口ModuleContext和它的locateService() 方法。
package org.osoa.sca; public interface ModuleContext { … Object locateService(String serviceName); } |
locateService() 方法有一个服务名称的输入函数,返回一个可访问该服务的对象。返回的这个对象实现了服务对应的Java接口。
服务的名字必须定义在同一个SCA模块中。服务的名称可以是如下两种之一:
/ |
o 如果仅定义了一个服务,则service-name是可选的
以下代码为使用@Context标签定义模块上下文的例子。
Java类中的clientMethod() 方法用到了模块上下文,并以服务名称为参数调用了它的locateService() 方法。locateService() 方法返回的对象被类型转换成服务所定义的接口的类型。
package services.client; import org.osoa.sca.ModuleContext; import org.osoa.sca.annotations.*; import services.hello.HelloService; @Service(ClientService.class) public class ClientServiceImpl implements ClientService { @Context ModuleContext moduleContext; public void clientMethod() { HelloService helloService = (HelloService)moduleContext.locateServic("HelloService"); String result = helloService.hello("Hello World!"); … } } |
从非SOA组件实现中访问服务
本节描述了SCA模块中的非SCA组件如何访问服务。
使用模块上下文
SCA模块中的非SCA的代码可以在其实现中使用ModuleContext来寻找服务。非SCA的代码如果使用了SCA模块所在的同一个类加载器或其子加载器,则也会被认为是一个SCA模块的一部分。
以下代码为ModuleContext 的Java接口。
package org.osoa.sca; public interface ModuleContext { … Object locateService(String serviceName); } |
非SCA模块可以通过CurrentModuleContext类访问当前的ModuleContext,该类的定义如下:
package org.osoa.sca; public final class CurrentModuleContext { public static ModuleContext getContext() { … } } |
ModuleContext moduleContext = CurrentModuleContext.getContext();
只要模块上下文可用,即可调用它的locateService()方法来找到所请求的服务。以下例子演示了如何在一个JSP页面中使用模块上下文得到一个服务并调用它的方法。
pageEncoding="ISO-8859-1" import="org.osoa.sca.*, commonj.sdo.*, services.hello.*"%> index.jsp … ModuleContext moduleContext = CurrentModuleContext.getContext(); HelloService helloService = ( HelloService)moduleContext.locateServic("HelloService"); String result = helloService.hello("Hello World!"); … %> |
调用服务的方法
在上几节中阐述了获取服务的几种方法。在取得服务后,调用服务的方法就跟调用普通Java类的方法一样。
以下代码为调用实现了StockQuote接口的服务的getQuote方法。
package services.client; import services.hello.HelloService; import org.osoa.sca.annotations.*; @Service(ClientService.class) public class ClientServiceImpl implements ClientService { @Reference(name="helloService",required=true) private HelloService helloService; public void clientMethod() { String result = helloService.hello("Hello World!"); … } } |
如果所访问的服务的接口标记为了远程接口,则调用时使用的将会是远程的语义。方法参数和返回值都是“传值”,并且可能抛出ServiceUnavailableException异常,这是个RuntimeException。
来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/12639375/viewspace-151146/,如需转载,请注明出处,否则将追究法律责任。
转载于:http://blog.itpub.net/12639375/viewspace-151146/