OSGI进阶:第三章 与流行的 Java B/S 体系架构进行集成(一)

 由  ValRay 发布

3. 与流行的 Java B/S体系架构进行集成

在看完了上面的章节后,大家可能会想:OK,OSGi 是还不错,也大概知道了怎么样基于它去设计实际的项目,但对于 Java B/S 系统而言,OSGi 怎么和目前流行的体系架构集成呢,这恐怕是大部分读者为关注的问题。如果能解决这个问题的话,我想大部分人都会考虑在新的项目/产品中去使用 OSGi,毕竟 OSGi 带来的好处是非常明显的,在 本章节中,将和大家来一起搭建一个基于OSGi的Hibernate+Spring+Webwork的脚手架。

首先来谈谈愿景,看看想象中的这个脚手架应该是什么样的,脚手架是为了支撑应用开发的,所以要从基于此脚手架开发 Web 应用的方式,才能看出脚手架需要支持些什么。 如果具备一个这样的脚手架,之前留言板系统的留言列表模块就会这么开发: 编写留言 PO,根据 PO 生成映射文件,并将此 PO 注册到 Hibernate 模块中,这个和之前的开发方式没多大区别; 编写留言列表服务,并将其定义为 Spring bean,并通过 spring 注入 Hibernate 模块提供的通用 Dao 服务; 编写留言 Command 服务,但不是基于之前的简单 MVC 框架了,而是归入 Webwork,在这里只需要以 POJO 的方式进行编写即可了,将此 Command 的配 置注册到 Webwork 模块中,将此 Command 服务定义为 Spring bean,以通过 spring 将留言列表服务注入,并需要以 OSGi 服务的方式对外提供; 注册留言板应用。 按照之上的步骤即可完成留言列表模块的开发,来看看这种开发模式和传统的基于 Hibernate+Spring+Webwork 开发模式的不同:

传统开发方式 基于OSGi的新的开发方式
模块开发方式 多模块放入同一工程中开发或模块分为多工程,通过工程依赖的方式来开发。 每个模块做为一个单独的工程,并且不需要通过工程依赖的方式。
模块部署方式启动时加载所有模块,不可动态部署、更新和管理模块的状态。模块可动态部署、更新和管理。
Command 服务注册方式以Action File的方式写入统一的 xml 文件中,多人共同编写独立的描述 Command 服务的 xml 文件,通过扩展点的方式注册
维护。到 Webwork 中,按模块单独维护。
PO 注册方式以 mapping recource 的方式 写入统一的 hibernate.cfg.xml 文件中,多 人共同维护。通过扩展点的方式注册到 Hibernate 中,按模块单独维护。

为什么说基于 OSGi 后就不好使用这些开源框架了呢,原因其实非常简单,就在于这些开源框架都是基于统一管理和唯一的 classloader 来设计开发的,但基于 OSGi 后, 各个模块分工程开发,资源分布在不同的模块中,并且这些资源都位于不同的 classloader 中,这就是基于 OSGi 后造成的冲突,下面我们就来解决这些冲突,使得 OSGi 可以和 Hibernate+Spring+Webwork 很好的集成在一起,在此处使用的 Hibernate 的版本为:3.1.3;Webwork 的版本为:2.2.6。

3.1. 解决和Hibernate的集成

默认情况下 Hibernate 通过 hibernate.cfg.xml 中的 mapping resource 来加载归入 SessionFactory 中管理的 PO,在加载时 Hibernate 通过 Hibernate 类所在的 classloader 加载 Mapping resource 中配置的 hbm 映射文件,并通过 cglib 将 hbm 映射文件中指定 的 class 生成 proxy。

改为基于 OSGi 后产生冲突的地方就在于 PO 分散到不同的工程中去了,同时要保持 模块化的封装性,就不能所有人都来修改封装 Hibernate 模块里的 hibernate.cfg.xml;另外一个冲突点在于封装 Hibernate 的模块的 classloader 无法加载到位于其他模块的 PO 对象,只要解决了这两个冲突,基于 OSGi 使用 Hibernate 的问题就解决了。 要解决这两个冲突,需要解决的就是如何将其他模块的 PO 注册到封装 Hibernate 的模 块中,以及 Hibernate 的 Configuration 如何加载其他模块的 PO 和映射文件。 基于 OSGi 的可扩展性,要将其他模块的 PO 注册到封装 Hibernate 的模块中,通过扩 展点方式即可实现,首先来设计此扩展点,我们注意到 Hibernate 的 Configuration.addClass 加载 class 的方式可达到和 mapping resource 完全一样的效果, 那么就很简单了,扩展点中需要的仅为 po 的 classname,此扩展点设计完毕后如下所示:

图表 4 Hibernate PO扩展点

然后就要考虑如何获取扩展点的实现了,在第二个章节中已经演示了通过 IExtensionRegistry 获取扩展点的实现的方法。 获取到扩展点的实现后,需要的就是把 class 加入到 Hibernate 的 Configuration 中, OSGi 中每个 Bundle 都是独立的 ClassLoader,那也就是说 Hibernate 所在的这个 Bundle 是无法加载到扩展点中 className 对应的类的,所幸的是 IExtension 的 IConfigurationElement 提供了初始化扩展中 class 的方法,也就是说可以实现在扩展 点的模块中直接创建提供扩展的模块中的类,实现的方法是:

IExtension[] extensions=registry.getExtensionPoint("HibernateModule.Hiber nateExtension").getExtensions(); 

for (int i = 0; i < extensions.length; i++) { 
IConfigurationElement[] elements=extensions[i].getConfigurationElements(); 
for (int j = 0; j < elements.length; j++) { 
poClass=elements[j].createExecutableExtension("class") .get
Class();

通过这样的方法就在封装 Hibernate 的模块中创建出了扩展的 PO 的 Class 实例,创建出此实例后即可通过 Hibernate 的 Configuration.addClass 将此 PO 加入到 SessionFactory 的管理范围内,这样就解决了那两个冲突,实现了基于 OSGi 的 Hibernate 的扩展。

上面的实现方式解决了静态时 Hibernate 加载其他模块中的 PO 初始化 SessionFactory 的问题,但记住要保持好基于 OSGi 的系统的动态性的特征,要保持动态化,就得监听 Hibernate 模块这个扩展点的扩展实现的变化情况,当系统中增加了新的需要归入 SessionFactory 管理的 PO 时,需要动态的加入到目前的 SessionFactory 中,当已有的 PO 从系统中删除时,也需要动态的将其从目前的 SessionFactory 中删除,不过 Hibernate 的 SessionFactory 是不支持动态的删除和增加其中管理的 PO 的,当发生变化时,只能重新初始化 SessionFactory 了。 根据上面的这些分析,终我们将 Hibernate 的封装模块设计为两个服务和一个扩展点构成:
Hibernate PO 扩展点

该扩展点定义如下:

<extension-point id="HibernateExtension" name="cn.org.osgi.hibernate.extension" schema="schema/hibernateExtension.exsd"/>

hibernateExtension.xsd的定义如图表 4所示。 SessionService

SessionService 负责 SessionFactory 的管理和对外提供 Session 的管理(获取、关闭 Session),在 SessionService 被激活时初始化 SessionFactory,初始化

SessionFactory 的代码如下所示:

 private void initSessionFactory(){

Class poClass=null;
try{
if(sf!=null){ sf.close();
}

Configuration config=(new 

Configuration()).configure(_configFile);

 for (Iterator iter = 
poExtensions.iterator(); iter.hasNext();) { 
 
 IExtension extension = (IExtension) iter.next(); 

IConfigurationElement[] elements=extension.getConfigurationElements(); 
  
for (int j = 0; j < elements.length; j++) { 
     
 poClass=elements[j].createExecutableExtension("class") .getClass ()
; 

 config.addClass(poClass); 

  } 
 } 
 _
sf=config.buildSessionFactory(); 
 info("已初始化SessionFactory"); 
} 

catch(Throwable t){      error("初始化Hibernate SessionFactory时出现错误",t); 
throw new RuntimeException("初始化Hibernate SessionFactory错误:"+t); 
} 
} 其中的poExtensions在激活SessionService组件时填充: 

IExtension[] extensions=registry.getExtensionPoint("HibernateModule.HibernateExtension").g etExtensions();       

for (int i = 0; i < extensions.length; i++) {           poExtensions.add(extensions[i]); 
        }

SessionService 组件还需实现 IRegistryChangeListener,以保证 SessionFactory 能动态的管理需要归入其管理的 PO: public class SessionComponent implements

SessionService,IRegistryChangeListener{     public void registryChanged(IRegistryChangeEvent event) { 
IExtensionDelta[] deltas=event.getExtensionDeltas("HibernateModule", 
"HibernateExtension");          if(deltas.length==0) 
 return; 
      
for (int i = 0; i < deltas.length; i++) {           switch (deltas[i].getKind()) {              case IExtensionDelta.ADDED: 
                poExtensions.add(deltas[i].getExtension()); 
                break; 
        
case IExtensionDelta.REMOVED: 
                poExtensions.remove(deltas[i].getExtension()); 
                break; 
            default: 
                break; 
            } 
    } 
        initSessionFactory(); 
    } 
}

注册 SessionService 组件为扩展变化的监听器:

registry.addRegistryChangeListener(this,"HibernateModule");

通过以上步骤即实现了动态的加载和卸载其他模块的 PO。 CommonDaoService

CommonDaoService 对外提供了一些通用的数据库操作的接口,如 save(Object obj)、update(Object obj)、getListByPage 等。

按照上面的步骤完成后,可编写一个 Bundle 来测试下 Hibernate 封装模块是否可用,启动后将会出现如下错误:

entity class not found: cn.org.osgi.bulletin.po.Bulletin

这是为什么呢? 根据错误信息的堆栈可看到有这么一行:

ReflectHelper.classForName

打开ReflectHelper类可以看到Hibernate会根据映射文件中的classname去实例化该 Class,而不是直接使用我们通过 Configuration.addClass 时传递给 Hibernate的Class,直接使用Class.forName的方法实例化扩展出的PO,自然会出现上面的错误,因为Hibernate类所在的ClassLoader和Bulletin类所在的 ClassLoader 并不同,碰到这样的情况,就得使用 OSGi 提供给 Bundle 的 DynamicImport-Package 了,使用此属性 OSGi 就可以在运行期动态的为这个 Bundle获取其他Bundle Export的Package' ;&,"vIE' ;&,"要求PO所在的 Bundle将PO的 Package Export,打开封装 Hibernate 的 Bundle 的 MANIFEST.MF 文件,在其中加上这一行:

DynamicImport-Package: *

然后在 cn.org.osgi.bulletin.po.Bulletin 的 Bundle 的 MANIFEST.MF 中加上 Export-Package: cn.org.osgi.bulletin.po;

加上这些后再次启动,发现在控制台中没有了之前的那个错误,但又出现了一个新的错误: java.lang.NoClassDefFoundError:org/hibernate/proxy/HibernateP roxy 这个错误对于延迟加载而言会有不小的影响,因此我们需要追查此错误的原因,根 据错误堆栈信息,可追查出是 cglib 中的AbstractClassGenerator.create方法执行时出现了错误,找出AbstractClassGenerator的源码,跟踪后发现是在此类中无法找到HibernateProxy,是不是有些奇怪呢? 仔细来分析下,为什么明明在同一个 Bundle 下的两个 jar,却加载不到呢?问题必 然还是出在 classloader 上,仔细看 create 方法,会看到其中有个 getClassLoader(),跟踪调试看 getClassLoader()就会发现,当为 Bulletin 生成 Proxy 时,这个时候的 ClassLoader 变成了 Bulletin 所在 Bundle 的 ClassLoader 了,不用说,用这个 ClassLoader 去加载 HibernateProxy 自然是加载不到了,找到了问题的根源,很明显需要 hack 下 AbstractClassGenerator 这个类了,把它的 ClassLoader 改为使用当前类所在的 ClassLoader,即:

// FIXME:Hack For OSGi           if(t==null){           t=this.getClass().getClassLoader(); 
}

OK,改完后重启,一切都好了,到这为止,可以说基于OSGi的Hibernate的扩展就封装好了。 相信细心的朋友们会发现这个Bundle还有不少需要改进指出:例如支持对于PO Class使用缓存的配置、支持多个连接不同库的SessionFactory等,这一切读者们都可以自己来完成,或者共同参与到OSGi.org.cn的基于OSGi的 Hibernate+Spring+Webwork的脚手架项目中来。

3.2. 解决和Spring的集成

和 Spring 的集成是 OSGi 必须解决的问题,毕竟 Spring 占据了目前大部分的 Java 应用领域,幸运的是 Spring 也发现了 OSGi 的好处,Spring-OSGi 的推出无疑让 OSGi 的忠实 fans 们更加的开心,同时也给 Spring 的用户体验 OSGi 所带来的好处的机会, Spring 和 OSGi 可以很好的结合在一起来满足企业应用的需求,这对于 OSGi 进军企业应用领域无疑是非常好的事。

对于目前版本的 OSGi(R4)而言,Spring 能带来的好处主要有这么两点: 不需要对外 Export 的服务可控制在 Bundle 范围内进行注入使用; 在不使用 Spring 时,只能将这些服务也通过 DS 以 OSGi Service 的方式对外提供,否则 Bundle 内的其他 Component 会无法通过注入的方式使用这个 Service,而在使用 Spring 的情况下则可将 Bundle 内的服务定义成 bean,并通过 Spring DI 注入到其他的 Component 中,例如留言列表模块中的留言列表服务、留言列表扩展点服务,这些都是不需要归入 DS 管理的。 这个带来的另外一个好处就是 Component 可以统一到一个描述文件里编写了,而不用像在 DS 里一样,每个 Component 编写一个新的描述文件,那样管理起来会比较的麻烦。 获取到 Spring 提供的 POJO Enhanced 的众多功能;

这个好处非常的明显,Spring 之所以成功其中重要的原因就是它的 POJO Enhanced 的支持,通过 Spring 的 POJO Enhanced 的支持,POJO 很容易就变成实现了企业应用复杂需求的功能类,例如远程调用、事务控制等,Spring 和 OSGi 的集成也就使得基于 OSGi 的应用很容易获取到 Spring 提供的这些好处,从而快速的实现企业应用的开发。 对于留言板这个简单的应用而言,在这里我们就只改进其中各个服务控制在 Bundle 范围内进行注册使用这一点,从而来说明 Spring-OSGi 的环境的搭建和使用的方法。

3.2.1. 搭建开发环境

首先来搭建 Spring-OSGi 的开发环境,根据对 OSGi 的了解,很容易知道,要实现 Spring 与 OSGi 的结合,必然是 Spring 会提供一些 Bundle 部署至 OSGi 框架中,有了这些 Bundle 后就可以使用到 Spring 提供的功能了,首先我们来了解需要部署哪些 Bundle 至 OSGi 的框架中: 从 Spring-OSGi 的官方网站: http://www.springframework.org/osgi 上下载 Spring-OSGi,在编写此篇Opendoc时的版本为 1.0 M3;

下载解压后可看到 dist 和 lib 两个目录,这两个目录中提供了我们搭建 Spring-OSGi 开发环境所需的 Spring 相关的 Bundle。 部署 Spring-OSGi 所需的 Bundle; Spring-OSGi 运行环境所需的 Bundle 为:
org.springframework.osgi.aopalliance.osgi 对应的 jar 文件为:aopalliance.osgi.jar
org.springframework.osgi.aspectjrt.osgi 对应的 jar 文件为:aspectjrt.osgi.jar
org.springframework.osgi.backport-util-concurrent 对应的 jar 文件为:backport-util-concurrent
org.springframework.osgi.spring-aop 对应的 jar 文件为:spring-aop.jar
org.springframework.osgi.spring-aspects 对应的 jar 文件为:spring-aspects.jar
org.springframework.osgi.spring-beans 对应的 jar 文件为:spring-beans.jar
org.springframework.osgi.spring-context 对应的 jar 文件为:spring-context.jar
org.springframework.osgi.spring-core 对应的 jar 文件为:spring-core.jar
org.springframework.osgi.spring-dao 对应的 jar 文件为:spring-dao.jar
org.springframework.osgi.spring-osgi-core 对应的 jar 文件为:spring-osgi-core.jar
org.springframework.osgi.spring-osgi-extender 对应的 jar 文件为:spring-osgi-extender.jar
org.springframework.osgi.spring-osgi-io 对应的 jar 文件为:spring-osgi-io.jar

在之前的 dist 和 lib 中找到类似上面所写的文件名的 jar 文件,并将其复制到 eclipse 的 plugins 目录(或通过外部 link 插件的方法;或直接 install 到 OSGi 框架中),启动 eclipse,此时在 eclipse 的 equinox osgi framework 中即可看到有如上插件名称的插件了,这样就完成了 Spring-OSGi 的开发环境的准备工作。

3.2.2. 在 Spring bean xml 中发布和引用 OSGi Service

在搭建好开发环境后,需要来学习下在 Spring-OSGi 中如何将 bean 发布为 OSGi Service,以及如何引用 OSGi Service,在发布和引用 OSGi Service 时希望做到的是 和使用 DS 时相同的效果。

要把一个 Spring bean 发布为 OSGi Service,只需在 spring bean 的 xml 中这么配置就行了:

在发布 OSGi Service 时,除了上面这些基本信息,还有需要经常用到的就是 Service 的 Properties 的配置了,通过在上面的 xml 元素下增加 osgi:service-properties 的节点 来实现,例如:

<osgi:service> 

<osgi:service-properties>

属性值

</osgi:service>
在发布 OSGi Service 的配置上 Spring-OSGi 还支持 lazy-init、depends-on 以及 context-classloader 这些属性配置,当 lazy-init 配置为 true 时此服务只有在被调用时才会激活;depends-on 可用于配置此服务所依赖的服务;context-classloader 用于配置使 用第三方的 classloader 来加载服务,例如 SpringWebApplicationContext 等。 要在 Spring bean 中引用 OSGi Service,只需在 spring bean 的 xml 中这么配置:

可以看出和 ds 中的配置基本是一致的,不过目前尚缺少对于 policy 这样的属性的配置,另外如要实现 bind 和 unbind 的设置,需要在 osgi:reference 的元素下增加 osgi:listener 的节点,例如:

bind-method=”服务可用时调用的方法” unbind-method=”服务不可用时的调用的方法”/> 

</osgi:reference>

这里 bind-method 和 unbind-method 的方法签名和在使用 DS 时稍有不同,这里 bind-method 和 unbind-method 的方法签名如下所示:

public void some-method-name(服务接口,Dictionary) 在引用 OSGi Service 的配置上 Spring-OSGi 还支持 filter、timeout、depends-on 和 context-classloader 这些属性配置,filter 属性用于配置查找的目标服务的过滤条件(例 如版本、名称、属性等);timeout 属性用于配置在服务不可用时等待的重试时间; depends-on 用于配置此引用的服务所依赖的服务;context-classloader 配置使用第三方 的 classloader(如 spring 的 WebcontextClassloader 等)来加载此 OSGi 服务。

3.2.3. 重构留言板列表模块

在学习了怎么发布和引用 OSGi 服务后,可以开始动手来重构之前的留言板系统了,在此以留言板列表模块为例来说明具体如何使用 Spring-OSGi ,同时体会 Spring-OSGi 所带来的优缺点。

Spring-OSGi 默认加载解析 META-INF/spring 目录下的 xml 文件作为 spring bean 配置文件,也可通过在 MANIFEST.MF 中增加 Spring-Context 来指定 spring bean 配置文件。 按照留言板列表模块的设计,其中留言板列表扩展点服务和留言板列表服务是不需 要列入 DS 范畴管理的,因此基于 Spring-OSGi 重构后将把其重构为 Spring bean,留言板列表 Command 服务则可基于 Spring 的 DI 方式注入所需的服务。 定义 Spring bean;

这步对于使用过 Spring 的用户而言是一件比较简单的事,在 META-INF 目录下 建立 spring 目录,在此目录下新建 springbeans.xml;

在此 xml 中定义留言板列表模块中的 bean,定义完毕后如下所示:

<bean name="bulletinListExtensionService"

class="cn.org.osgi.bulletin.service.impl.BulletinListExten sionComponent"/>



class="cn.org.osgi.bulletin.mvc.command.BulletinListComman d">

在 上 面 的 定 义 中 可 能 会 引 起 大 家 疑 问 的 地 方 是 bulletinListExtensionService明明是依赖IExtensionRegistry服 务的,为什么没定义呢,还有 bulletinListService 明明是依赖 CommonDaoService的,原因就在于这两个bean所依赖的都是其他bundle 所提供的服务,对于其他bundle所提供的服务仍然遵照OSGi的方式使用,也就是要通过引用OSGi服务的方式来配置。 定义所需引用的 OSGi 服务; 对于所需引用的 OSGi 服务,推荐采用另外的单独的文件来配置,因此在 spring 目 录 下 新 建 一 个 osgiservces.xml , 配 置 bulletinListService 和 bulletinListExtensionService 所需的服务,配置完毕后如下所示:






可以看到,对于需要引用 OSGi 服务的 bean 在这里采用了 osgi:listener 的方式,而不是直接在 bean 中采用的方式,这是为了维持 OSGi 系统的动态性,以便引用此 OSGi 服务的 bean 能够动态的获取服务的状态。 定义所需发布的 OSGi 服务; 留言板列表模块中的留言列表 Command 服务需要发布为 OSGi 服务,仍然在 osgiservices.xml 中进行配置,配置完毕后如下所示:

<osgi:service id="BulletinListCommandService" ref="bulletinListCommand"   interface="cn.org.osgi.opendoc.bulletin.service.WebCommand

" lazy-init="true">

LIST

运行重构后的留言板系统; 在运行前,需要首先将之前以 DS 方式定义的 OSGi 服务的部分删除,这步非常简单,直接把留言板列表模块中的 OSGi-INF 目录删除;

打开 MANIFEST.MF,将其中的 Service-Component 项删除;

在之前的运行的留言板系统的插件中增加 Spring-OSGi 所需的插件,点击运行;

运行后访问http://localhost/bulletin,会出现Command【LIST】服务不可用的错误, 造成这个错误的原因是留言板列表模块和Spring-OSGi的那些插件是同时启动 的,而根据Spring-OSGi的要求,留言板列表模块是要晚于Spring-OSGi启动的; 调整Spring-OSGi的那些插件的StartLevel为 2,重新启动留言板系统,通过 http://localhost/bulletin访问,可看到一切和之前的留言板系统保持一样了。 按照以上的步骤对其他的 Bundle 进行重构,重构完毕后即将这套留言板系统改造为基于 OSGi+Spring+Hibernate 了。

3.2.4. 小结

通过本章节学习了如何基于 Spring-OSGi 来实现 OSGi 与 Spring 的集成,与 Spring 的集成使得基于 OSGi 的应用能够很容易的实现企业应用的一些常见需求,如事务的控制、远程调用等。 在本章节中主要介绍的是 Spring 与 OSGi 的衔接部分,至于如何增强 Spring bean 的功能(如让 bean 具备事务功能等),这些可以参见 Spring 的 Reference,另外 Spring-OSGi 除了本章节中所写的 OSGi 服务的配置外,还支持 osgi:bundle、 osgi:config 等等配置,具体可参见:

http://blog.csdn.net/shuyaji/archive/2006/11/17/1393272.aspx Spring-OSGi规范 V0.7 中文版

http://www.springframework.org/osgi/specification Spring-OSGi规范V0.7 英文官方版 Spring-OSGi 带来的优势有: Bundle 内服务的注入支持,这样就不需要把内部的服务发布为 OSGi Service 了; 企业应用所需的技术的支撑,例如事务管理、远程调用,Spring 的这些功能支撑增强了 OSGi 进军企业应用领域的资本,避免了基于 OSGi 去做企业应用时需要做 N 多的重复性的工作; 支 持 以 第 三 方 的 classloader 去 加 载 OSGi Service , 如 WebApplicationContextClassLoader 等。

Spring-OSGi 值得改进的地方: 形成 Spring microKernel,目前的 Spring kernel 仍然是太大了,例如在留言板应用上需要的其实只是 spring core 的功能,但却需要引用到非常多的 bundle,也许侧面反应了 Spring 的模块化做的也不够的好;
Spring 本身所支持的功能的模块化的支撑,例如 Spring-DAO、Spring-MVC 这 些,应该做到能够切实的支撑模块化的开发; 无需设置启动顺序,需要设置启动顺序来启动基于 OSGi 的应用被认为是 OSGi Bad Smell 中非常典型的一种,在这点上 Spring-OSGi 也许可以考虑使用扩展点的方式来实现; 动态性方面,目前的Spring-OSGi在动态性方面还没有达到OSGi所支持的效果,例如 Bundle 更新时,并没有同时更新其所引用和发布的 OSGi Service 的信息。 鉴于 Spring 强大的 POJO Enhanced 功能,当 Spring-OSGi 提供的功能完全和 DS 匹配时,对于企业应用而言 DS 就可以隐藏在后台了,而 osgi:bundle 这些可为不熟悉 OSGi 的人来继续采用 Spring bean xml 配置的方式来定义 bundle,但在 bundle 这部分我还是更推荐继续采用 OSGi 的方式:分工程,通过 MANIFEST.MF 方式定义 Bundle 的基本信息、import、export 的 Package 等,Spring 和 OSGi 的完美结合是非常值得期待的; 但对于非企业应用的一些简单应用而言,则不一定需要 Spring 提供的那些复杂的技术 功能的支持,在这种情况下也许 OSGi 在 R5 时应该考虑为 DS 增加 scope 的概念。


wmz 2016-04-01 08:16

OSGi最优秀的B/S开源开发平台JXADF,http://osgia.com 有在线演示。

顶(9) 踩(0) 回复
查看评论