记得我在推广SCA规范的时候,常常和Spring作比较,Spring广为流传很大的一点就是在于它的IOC理念,SCA中也很彻底贯彻了这点(这点应该是个趋势,包括OSGI等等开源框架),但是也正是这个理念,在实际运用当中会带来困扰。当开发系统越来越大,一个工厂里面的bean组装复杂度不断增加,庞大的spring bean factory就好比一个大锅子,越来越多配置交织在一起,最终模块与模块之间无法分割,架构师虽然规划了很好的目录结构以及配置文件,但是在运行期的结构依然是耦合性极强,难以分割的业务模块逻辑团。这样的系统所面临的问题就像当初OO要解决的问题一样,只是上升到了业务级别:业务耦合性强,需求变更适应能力弱,维护成本高,无法剥离较为独立的业务组件提供复用,模块与模块之间牵制性强等。
SCA规范中描述的元数据就是Composite和Component,在代码级别的概念中Component就是Spring的bean,Composite可以看作Spring bean factory(其实使用Spring也可以实现SCA,只是如果使用factory来作为composite那么可能在性能上和可扩展性上还有一些问题)。在业务级别的设计中Composite就是业务模块,Component就是业务内部的业务实现逻辑单元,同时引入了Service和Reference的概念,将服务和引用单独作为内部逻辑单元,同时定义了Service和Reference的两种级别(Composite和Component),达到了业务实现作用域的控制,真正做到了业务组件级别的封装。
应该来说,除了开放性的特质以外,业务模块封装的特质是SCA的模块化最突出的优势,也是解决系统日益庞大情况下,如何降低维护成本,如何适应需求变更,如何提高开发效率的有效手段。但就是规范中的这一点,Tuscany的实现,不得不让我由原来的基于Tuscany架构二次扩展开发的想法做了转变,同时在后面对于服务框架的需求不断发展的情况下,对于Tuscany在服务框架中的定位不断的作着改变。
Tuscany在业务模块封装上面究竟有什么问题呢?在Tuscany中提供给第三方嵌入的SCA容器EmbeddedSCADomain结构如下:
EmbeddedSCADomain运行期结构图
上面的图展示了EmbeddedSCADomain如何载入外部的Composite到容器中,这里所用的一个技巧,就是include,Composite可以include多个Composite。下图是一个很简陋的活动图,主要就是大致描述了EmbeddedSCADomain是如何加载所有的Composites的。这里面省略了Tuscany对于插件扩展的载入以及一些细节方面的处理。
<v:shape coordsize="21600,21600" id="_x0000_i1026" type="#_x0000_t75" style="WIDTH: 392.25pt; HEIGHT: 248.25pt"><v:imagedata src="5D230993.files/image003.emz" o:title=""></v:imagedata></v:shape>
EmbeddedSCADomain启动活动图
<o:p> </o:p>
根据上面两个图就出现了两个比较大的问题:
1. 首先EmbeddedSCADomain所有的Composite和资源都是根据固定的URI载入,但是这个或者是目录或者是jar,但是如果是目录中的jar将不会去解析,那么对于我们业务模块当前的开发要求,各个业务开发组会把不同的Composite最后打包到各个业务模块的jar中,这样就没有办法通过一个EmbeddedSCADomain去装载,互通就更加说不上了。不过这个问题不是根本性的问题。而后面2的问题是根本性的原则问题。
2. Tuscany让所有的Composite互通,是将所有的composite通过include到一个domainComposite中,在build的过程中将所有的Composite的内部components克隆到了domainComposite中,这样其实所有的Component就在一个Composite中,也就很方便的互通了。这样SCA框架的业务模型封装形同虚设,和spring一样一个大的factory没有什么区别,丢失了最大的一个优势。同时serivce和reference都没有两种级别之分,业务模块化就无法实现和控制。
<o:p> </o:p>
就这样两个问题,让我需要考虑重新基于Tuscany的部分内核机制来重新构建容器装载,解析,组装机制。下图是ASF(Application Service FrameWork)的运行期结构设计图
<v:shape coordsize="21600,21600" id="_x0000_i1027" type="#_x0000_t75" style="WIDTH: 377.25pt; HEIGHT: 250.5pt"><v:imagedata src="5D230993.files/image005.emz" o:title=""></v:imagedata></v:shape>
<o:p> </o:p>
<v:shape coordsize="21600,21600" id="_x0000_i1028" type="#_x0000_t75" style="WIDTH: 255.75pt; HEIGHT: 318.75pt"><v:imagedata src="5D230993.files/image007.emz" o:title=""></v:imagedata></v:shape>
ASF(Application Service FrameWork)的运行期结构设计图
问题一的解决方案:
ASF中定义了真正包容所有Composite的Service Container,创建的过程中,通过搜索Classpath中所有的有composite-load-config.xml文件的jar,composite-load-config.xml定义了需要装载的Composite,然后resolve这些jar的所有的resource,根据定义要加载的内容动态加载所有需要加载的composite。
<o:p> </o:p>
问题二的解决方案:
基于问题一的解决,然后在Container中记录各个composite的必要信息和状态,然后按照不同级别的service和reference组装所有的composite,最后激活所有的composite。
<o:p> </o:p>
这两个问题的解决,也标志着ASF的基础框架形成,后续的战斗真正开始。