在開放 SOA (OSOA) 專案發布《強大的組合:SCA、OSGi 與 Spring》白皮書後,這三大技術的結合引起廣泛關注。Spring Dynamic Modules 是結合 Spring 與 OSGi 的商業實現之一,而 Spring beans 可作為服務組件架構(SCA)的組件實現。Apache Tuscany 的 Java 實現建立在 Apache Felix (OSGi 框架) 之上,為 SCA 運行時提供完整基礎設施。
本系列將示範如何結合 Spring Framework 與 Apache Tuscany SCA Java 運行時,設計與開發 SCA 組件。透過範例與代碼片段,您將理解 SCA 與 Spring 結合的優勢,並學會建立分散式服務應用程式。本文著重於基礎設計原則:如何將 Spring beans 發布為 SCA 服務、如何在 Spring 應用程式中存取 SCA 服務與屬性。第二部分將深入探討進階特性,如多應用程式上下文處理與 Spring beans 中的 SCA 註解應用。
SCA 提供基於面向服務架構 (SOA) 的程式設計模型,核心理念是將業務功能作為一系列服務提供,組合成滿足特定業務需求的解決方案。SCA 特色包括:
SCA 以「組合」描述應用程式結構與關聯,組合包含組件、服務、參考、屬性宣告及其關聯描述,可分組鏈接不同實作技術的組件,部署於 SCA 域中。
Spring 是開源專案,旨在透過解決企業應用開發複雜性來提升 J2EE 環境適用性。其分層架構允許選擇性使用組件,為簡單 Java 物件 (POJO) 提供框架,使其透過包裝類與 XML 配置使用 J2EE 容器。Spring 常被稱為「輕量級容器」,更精確的比喻是「簡化開發的框架」。
Apache Tuscany 致力於實作 SCA 規格 (含 Service Data Objects 與 Data Access Service 等相關規格)。遵循 OSOA 與 OASIS SCA Java 規格標準,為 SCA 運行時提供全面基礎設施。本文範例使用 Apache Tuscany V1.5 (撰寫時最新版)。
Spring 與 SCA 共享許多設計原則。SCA 將 Spring 視為組件實作技術之一,SCA Spring Component Implementation Specification 定義了使用方式。兩者相似處在於:組件皆可包含對其他服務的參考與可配置屬性。差異在於:SCA 是跨語言的分散式組件架構,支援多種通訊機制。透過將 Spring beans 發布為可被其他組件存取的服務、提供關聯到遠端組件服務的參考,SCA 擴展了 Spring 組件功能。
有效整合策略:使用 Spring 構建「粗粒度」服務組件實作,引入 SCA 以發布服務、連接服務組件、處理異構與分散式系統。SCA 為 Spring 應用程式增加實用功能:
在 Apache Tuscany 中,SCA 使用 Spring 作為組件在組合中的實作技術。透過 <implementation.spring> 元素在 SCDL (Service Component Definition Language) 中定義:
<composite xmlns="https://www.osoa.org/xmlns/sca/1.0"
xmlns:tuscany="https://tuscany.apache.org/xmlns/sca/1.0"
targetNamespace="https://calc"
xmlns:c="https://calc"
name="Calculator">
<component name="CalculatorServiceComponent">
<implementation.spring location="targetURI"/>
</component>
</composite>
location 屬性可指定:
<implementation.spring location="application-context.xml"/><implementation.spring location="./spring"/> (需包含 META-INF/MANIFEST.MF,以 Spring-Context 標頭指定上下文路徑)<implementation.spring location="spring.jar"/> (同樣需 MANIFEST.MF 與 Spring-Context 標頭)以計算機組件為例:CalculatorComponent 依賴 AddComponent (JavaScript)、SubtractComponent (POJO)、MultiplyComponent (POJO)、DivideComponent (Groovy) 四個不同技術實作的組件。SCA 組合檔 calculator.composite 定義組件、服務、參考與關聯:
<composite xmlns="https://www.osoa.org/xmlns/sca/1.0"
xmlns:t="https://tuscany.apache.org/xmlns/sca/1.0"
targetNamespace="https://calc"
xmlns:c="https://calc"
name="Calculator">
<component name="CalculatorComponent">
<implementation.spring location="META-INF/spring/calculator-context.xml"/>
<service name="CalculatorService">
<interface.java interface="calculator.CalculatorService"/>
<t:binding.rmi host="localhost" port="8099" serviceName="CalculatorRMIService"/>
</service>
<reference name="addService" target="AddComponent" />
<reference name="subtractService" target="SubtractComponent" />
<reference name="multiplyService" target="MultiplyComponent"/>
<reference name="divideService" target="DivideComponent" />
</component>
<component name="AddComponent">
<t:implementation.script script="calculator/AddServiceImpl.js"/>
</component>
<component name="SubtractComponent">
<implementation.java class="calculator.SubtractServiceImpl"/>
</component>
<component name="MultiplyComponent">
<implementation.java class="calculator.MultiplyServiceImpl"/>
</component>
<component name="DivideComponent">
<t:implementation.script script="calculator/DivideServiceImpl.groovy"/>
</component>
</composite>
注意:未明確宣告 <service> 的組件,SCA 運行時預設使用 binding.sca 發布;參考同樣預設使用 binding.sca 連接。
calculator-context.xml 定義業務邏輯與依賴:
<beans xmlns="https://www.springframework.org/schema/beans"
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
xmlns:sca="https://www.springframework.org/schema/sca"
xsi:schemaLocation="
https://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
https://www.springframework.org/schema/sca
https://www.osoa.org/xmlns/sca/1.0/spring-sca.xsd">
<bean id="Calculator" class="calculator.CalculatorServiceImpl">
<property name="add" ref="addService"/>
<property name="subtract" ref="subtractService"/>
<property name="multiply" ref="multiplyService"/>
<property name="divide" ref="divideService"/>
</bean>
</beans>
此處 Calculator bean 透過屬性引用組合中定義的 SCA 參考。若要將其發布為服務,需在上下文中宣告對應的 SCA 服務、參考與屬性。
使用 Spring SCA 命名空間的自定義元素在上下文檔中宣告:
<sca:service>:控制哪些 Spring bean 發布為 SCA 服務,指定 name (對應組合中的服務名)、type (Java 介面完整名稱)、target (提供服務的 bean 名稱)<sca:reference>:宣告對組合中其他 SCA 組件服務的依賴,需指定 name (對應組合中的參考名) 與 type<sca:property>:宣告對 SCA 組件屬性的依賴,name 需與組合中的屬性名稱匹配範例:
<beans ... xmlns:sca="https://www.springframework.org/schema/sca" ...>
<sca:service name="CalculatorService" type="calculator.CalculatorService" target="Calculator"/>
<bean id="Calculator" class="calculator.CalculatorServiceImpl">
<property name="add" ref="addService"/>
<property name="subtract" ref="subtractService"/>
<property name="multiply" ref="multiplyService"/>
<property name="divide" ref="divideService"/>
</bean>
<sca:reference name="addService" type="calculator.AddService"/>
<sca:reference name="subtractService" type="calculator.SubtractService"/>
<sca:reference name="multiplyService" type="calculator.MultiplyService"/>
<sca:reference name="divideService" type="calculator.DivideService"/>
</beans>
SCA 運行時支援直接在 Spring 上下文中使用組合中定義的參考與屬性名稱作為 bean 參考,無需自定義命名空間元素。規則如下:
ref 直接設為組合中的參考名稱,類型由運行時從 bean 類定義內省驗證<sca:service> 時,所有頂層 bean 均發布為 SCA 服務,服務名稱即 bean 名稱;內部 bean 與抽象 bean 排除;實作多介面的 bean 會以類本身作為單一服務介面發布在 <list>、<set>、 中使用隱式參考時,若集合泛型為 List<?> 等非具體類型,Tuscany 無法內省確切類型,導致注入失敗。建議改用顯式 <sca:reference> 指定 name 與 type。
Tuscany 不支援建構子注入的隱式參考。必須顯式宣告 <sca:reference>,並在 <constructor-arg> 中使用 index 與 type 屬性指定參考:
<bean id="Calculator" class="calculator.CalculatorServiceImpl">
<constructor-arg index="0" type="calculator.AddService" ref="addService"/>
<constructor-arg index="1" type="calculator.SubtractService" ref="subtractService"/>
<constructor-arg index="2" type="calculator.MultiplyService" ref="multiplyService"/>
<constructor-arg index="3" type="calculator.DivideService" ref="divideService"/>
</bean>
<sca:reference name="addService" type="calculator.AddService"/>
... 其他參考宣告 ...
Spring 核心單元為應用程式上下文,可形成階層結構 (子上下文可見父上下文 beans)。預設 Spring 容器啟動時驗證所有 bean 配置,但包含 SCA 參考/屬性的上下文需由 SCA 運行時先建立有效 bean。
Tuscany 運行時 (基於 Spring 2.5.5) 載入 <implementation.spring> 指定的目標上下文前,會:
SCAParentApplicationContext,包含對應的 Spring beansGenericApplicationContext 建立目標應用程式上下文,指定 SCAParentApplicationContext 為父上下文此機制確保 Spring 容器驗證通過,同時 Tuscany 提供服務綁定基礎設施,依 SCDL 配置套用策略。
本文介紹了基於 Spring 應用程式設計開發 SCA 組件的方法,涵蓋顯式/隱式宣告 SCA 服務、參考、屬性,以及 SCA 運行時建立上下文的機制。SCA 與 Spring 結合形成強大組合:Spring 提供高效組件開發基礎設施,改善測試覆蓋與應用品質;SCA 提供 SOA 組件組裝建模、服務發布連接、異構分散式系統處理能力。
敬請期待第二部分:多應用程式上下文處理、Spring beans 中的 SCA 註解等進階主題。


