远程服务的实现
远程服务是指可以通过接入点发布出去的服务。发布了的服务可以被包含该服务组件的模块以外的客户端所访问。一个服务是否是远程服务是由服务接口所定义的。在Java实现中,这是通过给Java接口加上@Remotable 标签来实现的。通过Java类而不是接口来定义的服务是不可以作为远程服务的。而从WSDL portTypes 生成的Java接口则总可以是远程接口,详情见WSDL 2 Java and Java 2 WSDL一节。
以下代码为通过@Remotable标签标注为远程服务的Java接口。
package services.hello; import org.osoa.sca.annotations.*; @Remotable public interface HelloService { String hello(String message); } |
远程接口通常设计成粗粒度,以用于松耦合的交互。远程服务接口不允许方法重载。
通过远程服务接口交换的复杂数据类型必须使用能够兼容所有接口绑定实现的marshalling技术。例如,如果该接口通过Web Service绑定来发布,则该接口的参数必须为Service Data Objects
(SDOs) 2.0 [1] 或者 JAXB [2] 类型.
无论远程服务是被外部调用还是被模块内部的其他组件调用,数据的传递均为值传递。
远程服务在实现时,可以在调用中或调用后修改输入数据,或在调用后修改返回数据。但是对于一个远程服务进行的每次本地或远程调用,SCA容器应该确保对输入数据或发生在调用后对返回数据的修改应该对调用者不可见。
一个远程接口可以在接口定义中指明是否通过传引用来进行参数传递,以避免进行参数的值拷贝。允许传引用的远程服务的实现不应该允许在调用期间修改输入数据,也不能在调用后修改返回数据。
@AllowsPassByReference 标签可以用在接口或单个的方法上,用来定义是否通过传引用来进行参数传递。
以下代码为一个远程Java服务接口以及实现该接口、并通过传引用来传递参数的Java组件的实现。
package services.hello; import org.osoa.sca.annotations.*; @Remotable public interface HelloService { String hello(String message); } package services.hello; import org.osoa.sca.annotations.*; @Service(HelloService.class) @AllowsPassByReference public class HelloServiceImpl implements HelloService { public String hello(String message) { ... } } |
package services.hello; import org.osoa.sca.annotations.*; @Service(HelloService.class) public class HelloServiceImpl implements HelloService { @AllowsPassByReference public String hello(String message) { ... } } |
本地接口的实现
本地接口只能被与该接口实现在同一个模块中的客户端所调用。本地服务无法通过接入点对外发布。
一个服务是否是本地服务是通过服务的接口来定义的。在Java中,没有@Remotable 标签的Java类就被认为是一个本地服务。
以下代码是一个本地服务的Java接口:
package services.hello; public interface HelloService { String hello(String message); } |
本地接口通常设计为细粒度的,用于紧耦合的交互。
本地服务的参数传递类型为传引用。这意味着客户端或服务提供者对参数(非简单类型)的修改都是见的。
不带标签的POJO的语义
没有标签和对应组件 定义文件的类也能在SCA模块中使用。由Java类所定义的服务接口被认为是一个本地接口。(正如以前所说,一个本地服务既可以是一个Java接口,也可以是一个Java类)。
类中的属性和引用都通过set方法暴露,无论其可见性属性如何。对于那些参数类型为复杂数据结构的set方法,SCA有可能无法判断传递的是一个属性或一个引用,因为两者都可以是一个复杂数据类型。但如果set方法带有@Remotable标签,则一定会被认定为是一个引用。当无法用这种方式声明参数类型时, 可以使用组件属性或引用来定义,只要其符合参数类型定义。
以基本数据类型为参数的Set方法总是代表类的属性。
有状态资源模式的实现
由SCA维护状态的服务,在其服务接口或服务实现类本身上有一个@Scope 标签。这种服务在SCA被称为有范围的服务。
@Scope 标签有如下几个属性:
value – 范围的取值
客户在调用有范围的服务时会根据范围取得不同的服务实例。目前支持的范围的取值包括以下几种:
stateless (默认) – 每个请求都被单独处理。Java实例可能会放在实例池中供调用。
request – 当处理一个远程服务时,所有本地服务调用都将由同一个服务实例完成。一个request的生命周期指的是运行期从一个客户端请求进入SCA,SCA启动一个服务线程到该线程同步地停止该服务的时候。服务定位在请求执行期间总会返回同一实例,因为request范围的请求总是绑定在创建它们的那个执行线程上。把一个@remotable 标注的远程接口指定为request 范围是非法的。
session – 同一个”会话”的所有请求都将由同一服务实例完成。一个session 范围的生命周期从会话建立开始到会话结束或会话失效的这段时间。同一客户端的后续请求都将进入同一个SCA会话范围。服务定位在会话存续期间都将返回同一个session范围的服务实例。SCA提供商不能修改session的定义,而是要求应用环境对每次传输绑定的”会话”进行对应。 “会话”的定义必须遵从在一个请求处理期间,同一个线程只能在至多一个会话的上下文中操作。例如,在JavaTM 2 Enterprise Edition (J2EE)应用环境中, session范围可绑定为一个HTTP会话范围。
module – 来自同一个模块的请求都将由同一个Java实例完成。一个模块范围的生命周期是指从一个模块组件在SCA运行期被装载以提供服务开始,到该模块被卸载或停止为止。注册表定位服务时在模块运行期间将返回同一个服务实例。
注意: 范围模型的定义是可扩展的,定义新的范围是被允许的。在未来版本中我们将描述如何扩展SCA运行期定义以处理其他的范围定义。
对于stateless, request 或 session 范围的实现,SCA运行期会避免并发调用这些实现实例的方法。不过module 范围的实现必须能够处理多线程并发调用它的方法。
对于双向接口, 即,既包含服务接口又包含回调接口,两种接口必须要求有兼容的范围定义。兼容的范围定义指的是其中一个接口的范围为stateless或两种接口的范围相同,其他任何情况都是不合法的。
以下代码为session范围的服务的接口和实现。
package services.shoppingcart; import org.osoa.sca.annotations.*; @Scope(“session”) public interface ShoppingCartService { void addToCart(Item item); … } package services.shoppingcart; import org.osoa.sca.annotations.*; @Service(ShoppingCartService.class) public class ShoppingCartServiceImpl implements ShoppingCartService { public void addToCart(Item item){ ... } … } |
一个有范围的接口可以在它的Java实现类上实现lifecycle 方法。这些方法在服务的范围开始或结束的时候被调用。Java的服务实现类通过@Init 标签标注的方法会在其范围开始、其属性和引用被注入后被调用一次仅且一次;通过@Destroy 标签标注的方法会在范围结束时被调用。
以下代码为带有lifecycle 回调方法的Java的服务实现类。
package services.shoppingcart; import org.osoa.sca.annotations.*; @Service(ShoppingCartService.class) public class ShoppingCartServiceImpl implements ShoppingCartService { public void addToCart(Item item){ ... } @Init public void start() { ... } @Destroy public void stop() { ... } } |
组件类型和组件
对于Java组件的实现来说,组件类型也可以通过文件来定义。组件定义文件能够被组件实现所在的ClassLoader所发现,并位于跟实现的命名空间所对应的目录下。它拥有跟实现文件相同的名字,所不同的是它使用.componentType 后缀名而不是.class 后缀名。
关于如何通过对组件实现进行类反射来添加组件定义信息的规则在《SCA组装模型规范》 [3]进行了说明。如果组件定义信息跟实现冲突,将会导致一个错误。如果一个组件定义文件指定的服务使用的WSDL接口,那么对应的Java类应该实现使用WSDL的JAX-WS映射所生成的Java接口。见WSDL 2 Java and Java 2 WSDL一节。
Java客户端和实现模型是从SCA组装模型的延伸来的。它提供的是对于Java接口类型系统和Java实现类型的支持。
以下代码为用于定义服务和接口引用的Java接口定义元素的schema定义。
interface.java 元素拥有下列属性:
interface – Java接口或Java类的完整名称
callbackInterface – 可选。Java回调接口的完整名称
以下代码为Java实现元素的schema定义。
implementation.java元素拥有下列属性:
implementation – 组件实现的Java类的完整名称
以下代码为Java组件实现的Java服务接口和Java实现类
package services.hello; public interface HelloService { String hello(String message); } package services.hello; import org.osoa.sca.annotations.*; @Service(HelloService.class) public class HelloServiceImpl implements HelloService { public String hello(String message) { ... } } |
以下代码为该组件实现的组件定义。组件的类型不需要在这里指明,因为可以通过Java类反射信息得到。
<?xml version="1.0" encoding="ASCII"?> |
以下代码为使用该实现的组件定义。
<?xml version="1.0" encoding="ASCII"?> name="HelloModule" > … … |
来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/12639375/viewspace-151145/,如需转载,请注明出处,否则将追究法律责任。
转载于:http://blog.itpub.net/12639375/viewspace-151145/