2007年9月24日Tuscany SCA 发布了V1.0版本的实现 。本文讲述的内容使用的就是基于这个版本的,代码下载地址 http://incubator.apache.org/tuscany/sca-java-10-incubating.html
一、Tuscany SCA 运行时的组成
Tuscany SCA V1.0 与前面的几个版本相比,在结构上发生了很大的变化。这种变化是意料之中的,但变化之快却是始料不及的。前面几个版本结构比较僵化、组织复杂,对变化的适应性差。如果SCA规范稍有变动,在结构上很难快速的适应,代码的变化就更不用说了。
Tuscany SCA V1.0版本将Tucany SCA 运行时(Runtime)分成两部分,核心部分和扩展部分。核心部分的实质是利用IoC (Inversion of Control)或者DI (Dependency Injection)原理将分开的逻辑和实现,通过扩展机制实现联系和匹配;在扩展部分的结构上使用多级扩展。这种机制带来更加灵活的扩展能力和动态特性。关于Ioc或者DI可以参看相关的文章。
通过扩展点将功能结构分解分散,减少了核心部分的对象和操作,使核心部分结构更加清晰,紧凑。这让我想起了章鱼:一个小小的头和长长的八只爪。我想不久,Tuscany SCA在结构上还会做进一步的改进。
二、"芝麻开门"——Tuscany SCA V1.0 的启动点
Tuscany SCA V1.0的启动是从SCADomain开始的,从上向下,由外到内逐步细化。SCADomain是一个抽象类,对应规范中的Domain组件。SCADomain通过其实现类获得Domain组件的实例。SCADomain 有几个实现类,关系如下图:

当执行 SCADomain.createInstance("someComposite") 时,SCA 的启动开始!
三、启动环境的准备
DefaultSCADomain是SCADomain的一个实现类。SCADomain.createInstance()通过DefaultSCADomain构造一个SCADomain类型的实例。这个DefaultSCADomain实例,包含了一个运行时(Runtime)对象——ReallySmallRuntime。
ReallySmallRuntime 主要作用就是实现扩展机制,做了大量的扩展点匹配的工作。
四、扩展机制
扩展机制包含两个部分:扩展类型和扩展点。扩展类型和扩展点的关系是接口和实现类的关系。
扩展类型声明的方法在扩展点中被实现;扩展点是一个接口,而扩展点是实现了这个接口的类。
在程序中,通过什么方法调用即避免在代码中不出现扩展点(实现类),还可以通过扩展类型(接口)使用这些扩展点(实现类)呢?来看看下面的代码:
ExtensionPointRegistry registry = new DefaultExtensionPointRegistry();
WorkScheduler workScheduler = registry.getExtensionPoint(WorkScheduler.class);
解释一下上面两行代码:
1、ExtensionPointRegistry是一个扩展点注册接口。在ExtensionPointRegistry 中声明的方法通过DefaultExtensionPointRegistry实现,通过ExtensionPointRegistry 接口来使用。
2、通过DefaultExtensionPointRegistry的实例registry来获取扩展类型为WorkScheduler.class 的扩展点,并返回一个扩展类型的实例。
ExtensionPointRegistry在这里起到了匹配、实例化、类型转换、存储的作用。
首先,通过ServiceConfigurationUtil.getServiceClassNames()方法匹配扩展点,方法如下。
public static List<String> getServiceClassNames(ClassLoader classLoader, String name) throws IOException {
List<String> classNames = new ArrayList<String>();
for (URL url: Collections.list(classLoader.getResources("META-INF/services/" + name))) {
InputStream is = url.openStream();
BufferedReader reader = null;
try {
reader = new BufferedReader(new InputStreamReader(is));
while (true) {
String line = reader.readLine();
if (line == null)
break;
line = line.trim();
if (!line.startsWith("#") && !"".equals(line)) {
classNames.add(line.trim());
}
}
} finally {
if (reader != null)
reader.close();
if (is != null) {
try {
is.close();
} catch (IOException ioe) {}
}
}
}
return classNames;
}
其中,String name参数是 WorkScheduler.class.getName()的值,即包含全部包在内的全路径名。
WorkScheduler.class.getName() = "org.apache.tuscany.sca.work.WorkScheduler";
在("META-INF/services/"路径下,会有一个以"org.apache.tuscany.sca.work.WorkScheduler"为名称的文件,文件内容为:
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
org.apache.tuscany.sca.core.work.Jsr237WorkScheduler
所以,ServiceConfigurationUtil.getServiceClassNames()返回的List类型的classNames里面有一个值,为:org.apache.tuscany.sca.core.work.Jsr237WorkScheduler
然后,实例化、存储、类型转换:
public <T> T getExtensionPoint(Class<T> extensionPointType) {
List<String> classNames = ServiceConfigurationUtil.getServiceClassNames(classLoader, extensionPointType.getName());
if (!classNames.isEmpty()) {
Class<?> extensionPointClass = Class.forName(classNames.iterator().next(), true, classLoader);
Constructor constructor = extensionPointClass.getConstructor();
Object extensionPoint = constructor.newInstance();
}
addExtensionPoint(extensionPoint);
return extensionPointType.cast(extensionPoint);
}
这样,通过ServiceConfigurationUtil.getServiceClassNames()查找与扩展类型匹配的扩展点,利用ExtensionPointRegistry.getExtensionPoint()方法实现实例化、类型转换、存储,实现了扩展机制。
五、启动过程中的扩展类型分级一览

除了上面列举的一些扩展类型之外,还有两个扩展类型需要特别说明。一个是XMLInputFactory扩展类型;另一个是ModuleActivator扩展类型,这个扩展类型不在上面的表中。