|
|||
| OfficialBlog | / | 200707 | |
|
OSGi Bundle 库(Repository)索引已开放(2007-07-31)翻译:草儿 审校:javavsnet OSGi Bundle库(repository)(OBR)是OSGi开发网站上最受欢迎的页面之一,它接收几乎和首页一样的点击率。因为OBR几乎没有做广告,所以这很冷人吃惊。 我们去年开发OBR提供一个唯一地OSGi开发者能够为他们的项目发现bundle的地方。OSGi联盟主要动力之一是提供一个统一的中间件平台,因此重用是重要的。想要重用,他必须找到合适的组件。开发OBR就是满足这种需要。 技术上它是如何工作的呢?其实,目前的OBR起源于Richard Hall的奥斯卡 Bundle 库,OBR与它一样是基于联盟库的思想。一个库是一个允许访问元数据和bundle地址的Web服务器。该信息能用于直接在一框架下安装bundle。例如,Richard为Oscar/Felix开发一个shell扩展,它从OBR下载一个bundle,并包括它的相关依赖。去年,我开发了一个允许浏览该库的Web接口。 在OBR下面你会发现repository.xml文件。该文件包含bundle的元数据并也能连接到其他库,因此OBR是一个联盟库。因为我们需要使人们尽可能的容易的向库提供bundle,所以这是一个重要的方面。在OBR模型中,任何公司或者个人能维护它自己的库并连接该库到其它的库。这个也使库在互联网上部分上是私有的,但它仍然可以向外部库提供访问。在这个模型中,OBR被访问点能够提供一个可信模型。 你在repository.xml发现的信息同在bundle中的信息是等量的但不完全一致。不完全一致的原因是在过去几年里,我们越来越清晰的知道OSGi技术需要一个更泛化的依赖模型。过去一段时间,我们已经增加了越来越多的依赖,象 Import-Package,Require-Bundle,Bundle-Required执行环境,Bundle-Native代码等等。这些依赖有它们自己的header和复杂性。尽管这些依赖有一些好处,但是我害怕再过一段时间它变得太复杂。因为这个原因,我们为OBR提供一个包括能力和需求的泛化模型。该模型与JSR124相似,但是我们通过构造OSGi的需求过滤器代替简单的属性文件使它功能更强大。基于过滤器的需求使得我们可能创建复杂的表达式并检查值。例如,一个需求可能是有一个比100x100像素大点的屏幕。JSR 124仅仅能处理精确匹配。 在某个特定时刻,一个OSGi环境有一个功能集。每一个bundle(或者硬件)要求一个功能集但是当被安装(它的要求满足以后)后也能提供一个新的功能集。这是一个非常好的高级模型。例如,如果你有一个移动电话并插入一个耳机,那么该电话将被扩展为具有耳机的功能。这个模型使得要求耳机的bundle能安装,反过来它提供新的功能。该模型工作如此之好,以至于Richard Hall改变了他在Apache Felix中的框架分解器(在它们能够启动以前该程序连线bundle)工作在泛化模式下。尽管我们发现一个与目前未被模型化的约束有关的一些错误场景,但是这个方案还是运行良好。 这个模型在一个在我们网站可访问的文档中得到描述。请注意该文档并不意味着OSGi联盟将继续开发这一个概念,我们仅仅测试一下想法。 手工维护repository.xml不是一个选项。单Eclipse就提供了超过1100个bundle。幸运的是,OSGi规范定义了很多提供元信息的 manifest header。因此我们开发了一个程序读取一系列的bundle和创建repository.xml文件。上个月我们得到OSGi联盟会议的授权可以开源此项目。这让企业可以包括一个bundle索引。源文件放在一个subversion服务器上,地址为http://www2.osgi.org/svn/public/trunk/org.osgi.impl.bundle.bindex/。 那么我们如何才能让OBR成功?除非你来帮助我们,我们才会有机会成功。在我的工作中我看到有那么多的公司开发可大量bundle,但这些bundle不是他们公司战略产品。如果我们想让建立一个统一中间件的主意成为现实,那么我们必须互相分享这些非战略bundle,从而我们不会得到串行端口bundle 的无数版本。 如果你有你想分享的这些bundle,那么建立你自己的库。这个相当容易。在这些bundle中元数据是绝对重要的。如果很多bundle(和JAR)没有名字,没有描述,没有授权信息,甚至什么都没有的话,那么这是一个灾难。花5分钟向一个 manifest增加这些信息,它将使bundle获得更多重用。所以你没有借口去忽视这个!如果你有文档化的bundle,那么你仅仅在你公司的Web 服务器上创建一个目录并在那保存bundle。到那时,一旦你在该目录上运行bindex,bindex创建repository.xml。唯一剩下的事情是将URL给我。我将它连接到主OSGi bundle库。所以你不要问能从OBR得到什么样的bundle,要想想你能给OBR什么。 希望看到你所有的Bundle库。 Peter Kriens 不活跃bundle的最佳实践(2007-07-09)翻译:javavsnet 审校:BlueDavy 经过一个活跃周期后,一些bundle觉得已经足够了,希望结束。他们小心的得到他们的Bundle对象并且缓慢的调用卸载……这种工作可在OSGi框架中完成么? 问题是stop()方法返回到一个刚刚被停止的bundle的方法。这意味着它的Bundle Context变为无效、服务被卸载以及classloader被释放,此时任何使用此Bundle的尝试都会抛出异常。由于这个原因,停止自己在 OSGI内循环中始终是不被赞成的。然而,在有些时候能够停止自己是有用的。在OSGI的R4中我们简要的接触了这个主题,但是没有付出足够的时间,所以我们把它顺延到下个版本。现在正是时候。 提议的解决方案是允许一个bundle调用一个异步的停止/卸载/更新方法。然而,在经过异常繁重有时甚至是激烈的讨论后,我们基本上得出了结论,停止自己或者停止其它buindle有着相同的问题。如果一个bundle被另一个bundle停止,始终存在着被停止的biundle没有被正确的停止而在被停止之后继续执行的可能性。从类装载的视角来看,这种情况是非常有害的。类装载器仅仅在他们不再被使用时才会被垃圾回收。只要一个类在某些线程的堆栈中运行,它就不能被垃圾回收。仅当使用OSGI机制时这个附加的问题才会发生。任何程序员停止了它的bundle,应该(显然的)停止执行代码,因为该bundle的停止方法已经被调用了,这是契约。 因此我们决定不增加附加的机制,让规格说明象现在这样。 然而,在这个领域的最佳实践是什么?最佳实践是在一个分离的线程中执行停止/更新/卸载方法。 void stopSafe(final Bundle bundle ) { new Thread() { public void run() { bundle.stop(); } }.start(); } 你有其它主意么? Peter Kriens 有人可以将OSGi的情况告诉Sun么?(2007-07-04)翻译:javavsnet 审校:草儿 有人刚发给我一个邮件链接JSR 316。该JSR将在Java EE 5的后继者JavaEE 6中的定义,而Java EE 5在JSR 244中定义。 在我们看JSR之前,让我们调查一下目前在企业计算领域的趋势。BEA把他们的微服务架构迁移到了OSGI之上,IBM Websphere 6.1 看起来会选择OSGI,Jonas 是一个从一开始就建立在OSGI之上的企业版框架,JBoss 微容器已修改支持OSGi。最重要的是,我们有一个令很多人Java企业版本反思的产品:Spring。现在,该产品掉入了OSGi爱河。但是市场清晰地告诉我们,一个产品不可能适合一切情况,OSGi亦是如此。我们将期待这些趋势会对JavaEE 6有一些影响么?唉,再一次思考。 为了表明一个产品不可能适合一切情况的问题,Sun提出了一些新的意见,叫做profiles。profiles肯定可以适合所有情况么?好的, profiles已经在J2ME中尝试了(对于为Java企业版工作的Sun的工程师来说,J2ME是专注于有限制的环境的JCP标准开发的另一条腿),以我的观点来看他们失败了。为规范而规范的Profiles对于实现代价是昂贵的。因此始终存在最小化profiles数量的动力。然而,在现实中因为需求的差别太大,所以对于一个特定的应用来说没有profile是完美的。因为profile不能完全符合实际要求,所以尽管profile只很多钱,但仍然使大多数人不满意。 这里有一个针对限量profiles的问题的简单解决方案:组件化。不是把大量Java API粘在一起到并称为profile,我们需要允许开发者准确地选择他们需要地组件。让开发者制造他们自己地profile!喔,难道这不是一个伟大的概念么? 对于这个解决方案我们需要些什么?是的,我们需要一个允许管理这些组件的组件框架。最好是动态的,以便我们在开发或者运行至关重要的商业应用时我们不必都重启服务器。我们同样需要一个模型,该模型使得组件能够合作且不要求有龌龊的边际效应的单例。那样的组件框架存在吗?是的,它叫OSGI/JSR291。 JSR316引用了OSGi/JSR 291么? 没有。 JSR 316仅仅在规范需求中提到了JSR 277,以一种相当间接的方式。他们说277正在到来,他们会推迟所有的决定直到277完成。因为277的数字看起来比291更老更成熟所以他们的决定是公正的?事实上277仍然在草案检验阶段,但291已经是最终版本了。因为291是基于非常成熟的规范的,该规范源于1999年,已经经历了4个主要版本。所以一定有另一种原因使得JSR291没有被提及。也许277会提供291没有特征?不是真的。看看JSR277的规范需求,你不能声称277的期望比JSR291/OSGI高:没有动态,没有类空间一直性,没有卸载,没有包导入,等等。他们早期的草案仍然处于一个过于简单的层次。277唯一真正高于 291的是储存库,而且有很多不严谨的地方。JSR277最近开放了邮件列表,看看列表中的讨论,看起来他们仍然在为一些基本的组件性斗争。然而,幸运的是,JSR277专家组已经许诺277模型系统可以和JSR291/OSGI交互。这使得选择OSGI是没有风险的,同时提供了附加的好处,现在OSGI 可以在很多Java虚拟机上运行(从1.2到6,也可以运行在嵌入式设备上),不象JSR277只能运行在Java7上,Java7会在2008年出来。为什么JSR316要等277?现在有现成的完美的解决方案291,而且JSR277许诺在将来会和291兼容。 用脚趾头都能想到在没有外界干涉的条件下,把JSR316建立在OSGi/JSR291之上是理所应当的事情。我想不到一条理性的理由,为什么JSR316今天不选择OSGi,所以我们就可以在Java企业版6中得到优势。你能想到理由么? Peter Kriens 声明还是不声明(2007-07-02)翻译:javavsnet 审校:BlueDavy 几周以前我描述了“hibernate”问题,怎样让多个bundle独立的使用Hibernate会话工厂而不需要互相了解。这些邮件不仅仅在寻找使用目前的规范来解决目前的问题的实践方案。这些邮件是我的研究课题。我在力图保持将来的OSGI规范干净而且符合正确的精神,所以我在玩弄选择权。下一次我会努力更加讲究实际。 我找到的共享会话工厂的解决方案是基于服务的,它允许bundle参与Hibernate的领域对象,而且它允许bundle使用一个领域对象的集合。然而,在这个解决方案中仍然潜伏着一个由于Hibernate特有的习惯导致的类装载的问题。在解决方案中这个问题通过一个简单的Require- Bundle来解决。然而,尽管这个方案可以工作,它很容易因为所需要的类重构进入其它bundle而崩溃。所以对于目前来说,这个方案足够好,对于将来我们需要理解根源问题并提出对这个根源问题的解决方案。让我们深入这个问题并分析正在发生着什么。 当Hibernate 创建一个会话工厂,它实际上创建了一个实现类的动态代理类。这在Hibernate中不是一个问题,虽然事实上它使用了客户的类装载器来创建代理。因此客户必须对于它没有使用的类有可见性。这就是说,Hibernate假设所有的类自己知道它对用户是可见的。在一个模块化的系统中,这个假设显然不成立的。一个简单的修正是让客户bundle使用Require-Bundle来访问Hibernate bundle,然而Require-Bundle有它自己的一系列问题,参见OSGi R4.1 规范。 我们可以搁浅工作然后告诉Hibernate和我们一起行动。然而,对于我们中的绝大多数来说这不是很有建设性的姿态。尽管OSGI技术日益普及,目前大多数JAR不是为彻底的模块化准备的。 这些类型的类装载问题是地方性的,因为在Java中缺乏象OSGI服务注册这样的核实的扩展机制,所以有很多开发者使用类装载器来实现本地扩展机制。当需要在虚拟机中共享相同的包的多个版本时,所有这些本地机制会崩溃。这些本地机制也不能提供类空间的一致性,而一致性对于可靠性是重要的。因此,最佳解决方案时OSGI规范直接提出这些议题。 OSGi CPEG要求我对于这个问题提出一个OSGi RFP,所以我和我最喜爱的OSGi邀请学者:Richard S. Hall做了交流。我们做了一些头脑风暴并在过去的几星期中开发了原型以便更好的理解问题。Richard修改了Apache Felix来支持我们的试验,我使用这些修改做了一个基于web的取便条应用,它使用了Hibernate。 我们使用的第一种方法时声明性“implicit-wire”指令。我们采用这个方案是因为问题的深层结构是:当你导入一个包,其结果是你应当导入附件的包。在Hibernate的例子中,当你导入了org.hibernate.cfg,你应该也导入 net.sf.cglib.*,即使你没有直接的依赖于这些包。Richard因此为导出包的子句创建了一个x-implicitwire指令。这条指令的值是当任何bundle导入该包时,一系列应该被附加导入的包。例如: Export-Package: org.hibernate.cfg;x-implicitwire:=”net.sf.cglib.proxy,net.sf.cglib.core,net.sf.cglib.reflect, org.hibernate.proxy” 如果Apache Felix依赖了org.hibernate.cfg包,它现在可以通过x-implicitwire指令自动导入需要的包,从而确保当Hibernate试图为会话工厂创建一个代理时,在做导入的bundle可以看到恰当的包。 声明式方法非常简单而且确实解决了问题。原型代码,一个简单的基于web的便条程序,工作良好。唯一需要变化的是创建hibernate bundle的bnd文件。然而,我们不确信这个方案可以解决所有的问题,在很多情况下带有x-implicitwire的声明式方法是不可行的。因为需要的隐含的依赖事先并不知道。一个关键的例子是普通的面向方面的编程,其附加的类是完全开放的。就是说,一个AspectJ程序可以在类中织入任何可能的类。 对这一问题的唯一解决方案是允许其它bundle在运行时添加导入。经过一些讨论后,Richard找到了勇气和时间,在bundle上下文对象中增加一个addRequire功能。用这种方式增加的导入与DynamicImport-Package 子句一样对待。就是说,直到导入被发现,这些导入才最后被查阅。 我创建了一个简单的扩展bundle,当其它 bundle被解析时可以检查他们。我选择导入org.hibernate.cfg包作为触发器。就是说,当一个bundle导入了这个包,它会自动得到 net.sfl.cglib.*的包。如同所预期的,这个方法工作良好而且不需要从客户bundle得到任何特殊信息,不需要任何变化。然而,不幸的是存在一个竞态条件,而我们没有一个好的解决方案。如果扩展bundle在客户bundle之后启动,我们会有一个问题。解析的客户bundle会在扩展 bundle有机会增加导入之前启动并创建一个会话工厂。作为另一种选择,附加的导入可以被持久性加入。在这种情况下,安装事件能够触发增加导入。这种情况下,竞态条件出现的窗口就很小了。这个问题被声明性方法的x-impliciwire阻止了。 那么什么是最佳解决方案?我确实不确定。我喜爱声明性方法的简洁性。当隐含的导入事先知道的情况下,它提供了一个干净而且非常简洁的方案。这个方法一个非常重要的优点是它没有竞态条件。然而,当这些导入是动态的,这个方法就不能用了。在运行时动态增加一个导入的程序性方法有所需要的灵活性,但是有竞态条件的问题。它需要部署者将扩展bundle的启动级别设置为开始级以确保它在客户bundle安装之前启动。 你怎么想? Peter Kriens |
||