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