1 Java 實現(xiàn)類型
1.1 簡介
該規(guī)范擴展自SCA裝配模型規(guī)范,定義了java類如何提供SCA組件的實現(xiàn),以及該類在SCA中是如何作為組件實現(xiàn)類型來使用的。
該規(guī)范需要用到所有《SCA的 Java注解和API規(guī)范v100》(本人正在翻譯)中定義的所有的注解和API。該文檔所引用的所有注解和API都是前者提到的規(guī)范所定義的,除非另行指定。SCA的 Java注解和API規(guī)范中定義的語義都是標準化的。
1.2 Java實現(xiàn)類型
這一節(jié)指出java類是如何提供SCA組件的實現(xiàn)的,包括各種屬性,如服務,引用和屬性。另外,它詳細列出了在作為組件實現(xiàn)類型的Java類上下文中,SCA的 Java注解和API規(guī)范中的元數據和Java API的使用方法。
1.2.1 service
基于Java類的組件實現(xiàn)可以提供一個或多個服務。
由基于Java的實現(xiàn)所提供的服務可以擁有按如下方法之一定義的接口:
l Java接口
l Java類
l 產生自WSDL portType的Java接口
Java實現(xiàn)類必須實現(xiàn)service接口定義的所有操作。如果服務接口是由某個java接口定義的,那么基于java的組件或實現(xiàn)該java接口,或實現(xiàn)接口的所有操作。
與java接口相比,其接口是通過java類定義的服務不是遠程的。產生自WSDL portType的Java接口是遠程的,細節(jié)可以查看SCA java注釋和API規(guī)范的WSDL 2 Java和Java 2 WSDL節(jié)。
Java實現(xiàn)類型可以指定通過@Service顯式提供的服務。以上情形下,@Service的使用并不是必須的,Java實現(xiàn)類型提供的服務可以從實現(xiàn)類自身繼承而來。
1.2.1.1 @Service的使用
服
務接口可以作為Java接口來指定。是組件實現(xiàn)的Java類,可以通過實現(xiàn)指定服務契約的java接口來提供服務。因為一個java類可以實現(xiàn)多個接口,
而某些并沒有定義SCA 服務,所以@Service注解可以用于表示由實現(xiàn)提供的服務以及他們相應的Java接口定義。
如下是java服務接口和使用該接口提供服務的Java實現(xiàn)的例子:
Interface:
public interface HelloService {
String hello(String message);
}
Implementation class:
@Service(HelloService.class)
public class HelloServiceImpl implements HelloService {
public String hello(String message) {
...
}
}
該實現(xiàn)的組件類型的XML描述如下。沒有必要指定component type,因為可以從Java類反射得到。
<?xml version="1.0" encoding="ASCII"?>
<componentType xmlns="http://www.osoa.org/xmlns/sca/0.9">
<service name="HelloService">
<interface.java inter>"services.hello.HelloService"/>
</service>
</componentType>
和接口相比,Java類實現(xiàn)本身也能定義由組件提供的服務。這種情況下,@Service可以被用于顯式地聲明定義了實現(xiàn)所提供的服務的實現(xiàn)類。同情形下,組件只能用@Service提供服務。如下所示:
@Service(HelloServiceImpl.class)
public class HelloServiceImpl implements AnotherInterface {
public String hello(String message) {
...
}
…
}
在上述例子中,HelloWorldServiceImpl提供了一個服務。該服務在實現(xiàn)類上定義為public方法。AnotherInterface接口沒有指定組件所提供的服務。如下是內省的組件類型的XML描述:
<?xml version="1.0" encoding="ASCII"?>
<componentType xmlns="http://www.osoa.org/xmlns/sca/1.0">
<service name="HelloService">
<interface.java inter/>
</service>
</componentType>
@Service可以用于指定由實現(xiàn)提供的多個服務:
@Service(interfaces={HelloService.class, AnotherInterface.class})
public class HelloServiceImpl implements HelloService, AnotherInterface {
public String hello(String message) {
...
}
…
}
如下片段演示了該實現(xiàn)的內省的組件類型:
<?xml version="1.0" encoding="ASCII"?>
<componentType xmlns="http://www.osoa.org/xmlns/sca/1.0">
<service name="HelloService">
<interface.java inter>"services.hello.HelloService"/>
</service>
<service name="AnotherService">
<interface.java inter>"services.hello.AnotherService"/>
</service>
</componentType>
1.2.1.2 本地和遠程服務
由接口定義的Java服務契約,可以使用@Remotable來聲明服務按照SCA裝配規(guī)范遵循遠程服務的語義。如下演示了@Remotable使用:
package services.hello;
@Remotable
public interface HelloService {
String hello(String message);
}
如果沒有聲明@Remotable,由Java接口定義的服務就被認為是SCA裝配模型規(guī)范里定義的本地服務。
如果實現(xiàn)類實現(xiàn)了沒有用@Remotable注解修飾的接口,那么該類被認為實現(xiàn)了單個本地服務。該本地服務的類型是由該類定義的。(注:本地服務可以使用Java接口或類指定類型)
某個實現(xiàn)類為SCA運行時提供關于是否能通過使用@AllowsPassByReference來完成不經過copy而傳值語義工作的信息。
1.2.1.3 內省Java實現(xiàn)提供的服務
上述情況下,由Java實現(xiàn)類提供的服務可以通過內省來決定,而可以忽略使用@Service指定的必要。如下的算法被用來決定服務是如何從實現(xiàn)類內省的。
如果SCA服務的接口在實現(xiàn)類上沒有用@Service注解指定,那么就假設所有的用@Remotable注解了的接口都是由組件提供的服務接口。如果沒有一個實現(xiàn)接口是遠程的,那么默認實現(xiàn)提供了單個服務,該服務的類型就是實現(xiàn)的class。
1.2.1.4 非堵塞型服務操作
由java接口或實現(xiàn)類定義的服務操作可以使用@OneWay來聲明SCA 運行時在客戶程序調用服務操作的時候必須遵循非堵塞性語義。該非堵塞性語義由SCA裝配規(guī)范(本人正在翻譯)定義了。
1.2.1.5 非會話和會話服務
Java實現(xiàn)類型支持所有的會話服務注解,這些會話注解在SCA Java注解和API規(guī)范中定義:@Conversational,@EndsConversational和@ConversationAttributes。
以
下的語義控制由Java接口或實現(xiàn)類定義的服務契約。由Java接口或實現(xiàn)類定義的服務契約隱式地表示非會話除非使用了@Conversational注
解修飾。一旦使用了@Conversational注解修飾,@Conversational就用于聲明提供服務的組件實現(xiàn)實現(xiàn)了會話語義。
1.2.1.6 回調服務
回調接口通過在某個Java類實現(xiàn)的服務接口上使用@Callback注解來聲明。
1.2.2 引用
引用可以通過注入或SCA Java 注解和API規(guī)范中定義的ComponentContext API來維護。只要可能,推薦使用注入方式來訪問引用。
1.2.2.1 引用注入
某個Java實現(xiàn)類型可以通過使用@Reference顯式地指定其引用,如下所示:
public class ClientComponentImpl implements Client {
private HelloService service;
@Reference
public void setHelloService(HelloService service) {
this.service = service;
}
}
如 果@Reference標記了某個public或protected
的setter方法,那么就要求SCA運行時提供指定了方法參數類型的服務引用契約的相應實現(xiàn)。通過調用實現(xiàn)實例的setter方法來完成這個工作。注入
什么時候發(fā)生是由實現(xiàn)的作用域(scope)定義的。然而,它總是在第一個服務方法被調用之前發(fā)生注入。
如果@Reference標記了某個public或protected的屬性域,那么就要求SCA運行時提供指定了屬性域類型的服務引用契約的相應實現(xiàn)。通過設置實現(xiàn)實例的該屬性域來完成。什么時候發(fā)生注入由實現(xiàn)的作用域定義。
如果@Reference標記構造函數的某個參數上,那么就要求SCA運行時提供在實現(xiàn)初始化時期指定了構造函數參數的服務引用契約的相應實現(xiàn)。
引用也可以根據XXX(這里原文有問題)節(jié)定義的規(guī)則通過內省實現(xiàn)類來指定。
引用可以是聲明選項(聲明選項在SCA Java注解和API規(guī)范中定義了)。
1.2.2.2 動態(tài)引用訪問
引用可以通過ComponentContext.getService()和ComponentContext.getServiceReference(.)方法來動態(tài)訪問。
1.2.3 屬性(Property)
1.2.3.1 屬性注入
屬性可以通過注入或ComponentContext API來維護。只要可能,推薦使用注入方式來訪問屬性。
Java實現(xiàn)類型可以通過使用@Property注解顯式指定它的屬性,如下所示:
public class ClientComponentImpl implements Client {
private int maxRetries;
@Property
public void setRetries(int maxRetries) {
this. maxRetries = maxRetries;
}
}
如果@Property標記了某個public或protected屬性域,那么就要求SCA運行時提供相應的屬性值。什么時候發(fā)生注入由實現(xiàn)的作用域(scope)定義。
如果@Property標記在構造函數的某個參數上,那么就要求SCA運行時在實現(xiàn)實例初始化期間提供相應的屬性值。
屬性也可以根據XXX(這里原文有問題)節(jié)定義的規(guī)則通過內省實現(xiàn)類來指定。
1.2.3.2 動態(tài)屬性訪問
屬性可以通過ComponentContext.getService()和ComponentContext.getServiceReference(.)方法來動態(tài)訪問。這問mponentContext.getServiceReference()
1.2.4 實現(xiàn)實例的初始化
Java實 現(xiàn)類必須提供一個public或protected
構造函數,以便SCA運行時用于初始化實現(xiàn)的實例。構造函數可以有參數;當存在參數時,SCA容器會在調用構造函數的時候傳遞可用的屬性或引用值。在任何
一個服務方法被調用之前,所有的屬性或引用值,都將會設置給屬性域或傳遞給與屬性相關的setter方法。
構造函數的選用由容器選擇,如下所示:
1. 用@Constructor注解標注的聲明的構造函數
2. 無二義性的標識所有屬性和引用值的聲明的構造函數
3. 無參數的構造函數
@Constructor注解只能在一個構造函數上指定;如果多個構造函數標注了@Constructor,SCA容器將報錯。
與構造函數的每個參數相關的屬性或引用用下列方式標識:
l @Constructor注解的by name(如果存在)
l 通過在參數聲明上使用的@Property或@Reference注解
l 通過唯一地與屬性或引用的類型匹配參數類型
組件間的循環(huán)引用發(fā)生的話,容器會用以下辦法之一進行處理:
l 如果循環(huán)中的任意引用是可選的(不是必須的),那么容器就會在構造期間注入null值。保證調用任何服務之前都已經注入了目標的引用。
l 容器也可以注入一個目標服務的代理;在代理上的方法調用可能會導致ServiceUnavailableException異常。
以下是合法的Java組件構造函數聲明的例子:
/** Simple class taking a single property value */
public class Impl1 {
String someProperty;
public Impl1(String propval) {...}
}
/** Simple class taking a property and reference in the constructor;
* The values are not injected into the fields.
*//
public class Impl2 {
public String someProperty;
public SomeService someReference;
public Impl2(String a, SomeService b) {...}
}
/** Class declaring a named property and reference through the constructor */
public class Impl3 {
@Constructor({"someProperty", "someReference"})
public Impl3(String a, SomeService b) {...}
}
/** Class declaring a named property and reference through parameters */
public class Impl3b {
public Impl3b(
@Property("someProperty") String a,
@Reference("someReference) SomeService b) {...}
}
/** Additional property set through a method */
public class Impl4 {
public String someProperty;
public SomeService someReference;
public Impl2(String a, SomeService b) {...}
@Property public void setAnotherProperty(int x) {...}
}
1.2.5 實現(xiàn)作用域和生命周期回調
Java實現(xiàn)類型支持在SCA Java注解和API規(guī)范中定義的所有作用域:STATELESS,REQUEST,CONVERSATION和COMPOSITE。實現(xiàn)通過使用@Scope注解指定它們的作用域:
@Scope(”COMPOSITE”)
public class ClientComponentImpl implements Client {
// …
}
當沒有在實現(xiàn)類上指定@Scope注解,默認為STATELESS。
Java組件的實現(xiàn)通過分別使用@Init和@Destroy來指定init和destroy回調。例如:
public class ClientComponentImpl implements Client {
@Init
public void init() {
//…
}
@Destroy
public void destroy() {
//…
}
}
1.2.5.1 作用域為CONVERSATION的Java實現(xiàn)類可能會使用@ConversationID注解來持有當前的會話ID。該會話ID通過public或protected屬性域或setter方法注入??蛇x地,Conversation API(在SCA Java注解和API規(guī)范中定義)能用來獲取當前的會話ID。
會話性的實現(xiàn)
作為會話服務的提供者,有必要在單個會話的連續(xù)的方法調用之間維持狀態(tài)數據。對于Java實現(xiàn)類型,有兩種可能的策略用于處理該狀態(tài)數據:
1. 實現(xiàn)可以構建為無狀態(tài)的代碼片(本質上來說,代碼認為對于每個函數調用都是新的實例)。代碼必須負責訪問會話的conversationID,該會話由SCA運行時維護。然后,在方法的處理過程期間和需要訪問持久化的狀態(tài)數據時,由實現(xiàn)來負責持久化任何必要的狀態(tài)數據,而所有都是以conversationID作為key來使用。
2. 實現(xiàn)可以構建為有狀態(tài)的代碼片,也就意味著實現(xiàn)把所有的狀態(tài)數據存儲在java類實例的屬性域中。實現(xiàn)必須用@Scope注解聲明為會話作用域。這就告訴SCA運行時環(huán)境,實現(xiàn)是有狀態(tài)的,并且SCA運行時必須在客戶函數調用與服務實現(xiàn)的某個特定實例之間扮演中介角色。如果運行時因為某種原因需要將實例清除出內存,運行時環(huán)境還要負責持久化和存儲實現(xiàn)的實例。(注:會話是非常長的生命期限,SCA運行時可以使用集群系統(tǒng)。在集群系統(tǒng)中給定的實例對象可以在集群的各個節(jié)點中移動,以實現(xiàn)負載均衡)
1.2.6訪問回調服務
Java實現(xiàn)類用@Callback注解來要求回調服務。該@Callback注解引用了在某個public或protected屬性域或setter方法上與當前調用注入相關的回調服務。
1.2.7未注解的實現(xiàn)的語義
這一節(jié)定義了并未使用@Reference或@Property顯式聲明的Java組件實現(xiàn)的屬性和引用的判定規(guī)則。
在沒有@Property和@Reference注解的時候,類的屬性和引用按以下規(guī)則定義:
1. 如果Java類型是由@Remotable注解的接口,就是引用。
2. 否則,如果Java類型是一個數組,并該數組元素的類型是由@Remotable注解的接口,那么就是引用。
3. 否則,如果Java類型是java.util.Collection的子接口或子類,并且collection的參數化類型是由@Remotable注解的接口,那么就是引用。
4. 否則就是屬性。
1.2.8在裝配中指定java實現(xiàn)
如下定義了用于java實現(xiàn)類型的實現(xiàn)元素schema:
<implementation.java class="NCName" />
Implementation.java元素有如下屬性:
class(必須) –實現(xiàn)的java類全名。
1.2.9指定component type
對于Java實現(xiàn)類,組件類型一般都是直接來自java類的內省。
在配置文件中component type的指定是可選的。組件類型配置文件由裝載java類的同一個類裝載器發(fā)現(xiàn)。配置文件必須在與實現(xiàn)的名稱空間一致的目錄下,并與java類擁有相同的名字,并用.componentType擴展名替代.class擴展名。
componentType side文件是如何加入到從組件的實現(xiàn)反射而來的組件類型信息中的規(guī)則在SCA裝配模型規(guī)范中定義了。如果組件類型信息與實現(xiàn)沖突,將產生錯誤。
如果componentType side文件用WSDL接口指定了服務接口,那么java類應該實現(xiàn)由JAX-WS的WSDL到java接口的映射而產生的接口。請查看”WSDL 2 Java和Java 2 WSDL”節(jié)