Avalon中的组件
Avalon Framework的核心是组件。我们定义它为“执行特定角色的被动实体”。
(1)passive API
被动实体必须使用passive API。passive API是被执行,相对于自己执行。详细解释参考IoC模式。
(2)特定角色
在设计系统架构时,要考虑系统中各种不同的角色。这样,你就会有一个组件的列表清单。
对于每一种角色,你要定义它的脚本,或对系统其它部分的接口。直接定义接口是不够的。要在定义你的接口时,要对特定契约进行定义,并保留在你的脑中。也就是说,组件提供给那些用户,生产出什么东西。在定义好接口和契约后,就可以来实现组件了。
(3)组件
组件是相互依赖的。那是为什么组件有各种不同关系的原因。Avalon Framework直接支持的组件关系有:配置、外部组件使用、管理和执行。
每一种关系都由一个单独的接口来描述。了解这些关系的优先顺序是重要的,这使我们了解它们如何整合在一起的所有契约。
1. Configurable:标记对象为可配置
2. Serviceable:标记对象为可使用组件
3. Initializable:标记对象为可初始化
4. Disposable:标记对象为可销毁
5. Stoppable:标记对象为可启动和停止
这种顺序契约意味着通过这些接口的每一种定义的方法,是被创建组件的对象按特定的顺序调用的。每种接口表示为一个被控制的组件或对象的狭窄视图。
Serviceable 在Avalon中,Serviceable被定义为控制或使用组件的活动实体。这和音乐作曲家很相似。作曲家在交响曲(系统)中根据他们的角色选择器具(组件),告诉演奏时的注意点。
Avalon Serviceable遵循IoC,被指派一个服务管理。下面的章节会讨论如何查找特定的组件,如何为Serviceable准备ServiceManger。
为了安全原因,Serviceable有一个特定契约。ServiceManger只能够被设置一次。这意味着,compose在ServiceManger设置成功之后,忽略其它所有设置ServiceManger的迸发请求。
查找组件
(1)服务管理
大多情况下,使用ServiceManger来获得你所需要的组件实例。在Avalon中,角色由组件的work接口来定义。work接口不同于其它接口,因为它是定义组件角色的接口。Serviceable和组件具有接口关系,因为它们的地址指定了组件的关系。
ServiceManger有一个查找组件的方法lookup(),根据work接口(角色)中的完全限定名字(FQN)来查找组件。下面是一个例子:
final MyComponent component = (MyComponent)manager.
lookup( "com.mycompany.myproject.MyComponent" );
需要注意的是角色和功能不是等价的。
(2)服务选择器
有时候,有好几个组件具有同一个角色的功能。这就需要使用ServiceSelector来选择实际的那个。例如,同一个角色有不同的格式:使用独立的组件实现根据规则格式化输入的文档。一种格式是将输入文档中所有Tab键替换为4个空格;一种格式是保留原样;而另一种格式是将输入文档格式化成一个canvas对象。对于Serviceable,实现代码没有什么不同,只是文本的格式不同。
使用前面的例子,我们意识到使用ServiceManger获得正确的组件是不适合的。组件地址就是角色的每个组件的关系。幸运的是,ServiceSelector是一个组件,我们可以使用ServiceManger来查找ServiceSelector。ServiceSelector被设计为从相同角色的多个组件中选择一个组件。下面是一个例子:
final ServiceSelector selector = (ServiceSelector)manager.
lookup( "org.mycompany.myproject.FormatterSelector" );
final Formatter formatter = (Formatter)selector.select( myURL );
(3)当使用完组件之后
ServiceManger和ServiceSelector都要求在使用完组件之后释放组件。使用的方法是release(),一种使用的方法是使用try/catch/finally结构,下面是一个例子:
MyComponent component = null;
try
{
component = (MyComponent) manager.lookup("org.mycom.MyComponent");
component.myMethod();
}
catch (Exception e)
{
getLogger().debug("Error using MyComponent", e);
}
finally
{
if (component != null) manager.release(component);
}
这样做的原因是从组件池中选择组件的高效组件管理能够正确的管理资源。