BT

如何利用碎片时间提升技术认知与能力? 点击获取答案

OSGi Bundle Convert插件原理

| 作者 陈旭东 关注 0 他的粉丝 发布于 2014年4月4日. 估计阅读时间: 29 分钟 | 都知道硅谷人工智能做的好,你知道 硅谷的运维技术 也值得参考吗?QCon上海带你探索其中的奥义

1.引言

普通的web应用要转换为OSGi应用,经常会遇到应用中依赖的Jar是非标准的情况,这些Jar可能只遵守了部分OSGi规范,甚至Manifest信息是空的。这种情况在OSGi 应用中根本无法使用这个非标准的Jar做为Bundle,故必须要将这个非标准的Jar转换成遵守OSGi规范的Bundle。另外用Maven管理的仓库,由于不同开发者对规范的理解不同,在仓库中也存在了各种规范或者不规范的Jar,如果我们能很好的将Maven仓库中的Jar转换成标准的Bundle,Maven仓库也就转换成对应的OSGi Bundle仓库,对于非OSGi的应用而言也就可以很方便的利用Maven仓库,普通web应用也可以平滑的切换到OSGi环境。

2.转换Bundle的方式

要将非标准的Jar转换成OSGi Bundle,最核心的也就是如何将Bundle中的Import-Package和Export-Package内容重写,对此转换Bunlde的方式可划分为3种方式:1.固定版本方式转换;2.非固定版本方式转换;3.固定版本和非固定版本混合使用方式转换;

2.1固定版本方式

主要依据Jar对应pom依赖树(mvn dependency:tree)进行转换,而对于pom中无法确定的版本,则需要依靠Bundle模块pom的依赖仲裁来强制选择一个版本,这种情况最终转换好的Bundle Import-Package和Export-Package是固定版本的;固定版本方式转换有点类似于maven中的Jar版本强依赖,这个Bundle必须import指定的固定版本Bundle,这样做的目的也在于使得转换后的每个Bundle依赖环境是一个独立的集合,而且集合之间没有任何冲突可言。

2.2非固定版本方式

依据Jar文件中*.class的package和import package信息转换,最终转换后的Bundle不指定Import-Package版本和Export-Package版本;这种情况也就是目前经常用的不指定版本范围或者无版本package,特别是无版本package,在OSGi环境中,将会使用Verison>=0.0.0的方式选择Bundle,只要最新版本可用,就会使用最新版本替换新环境。

2.3固定版本和非固定版本混合使用方式

依据pom依赖树转换,遇到无法转换的版本不继续处理,最终转换后的Bunlde中Import-Package和Export-Package会存在固定依赖版本、无版本信息或者版本区间。例:

Import-Package: org.apache.commons.collections.comparators;version="[3.2.0,3.2.0]
",org.apache.commons.collections.keyvalue;version="[3.2.0,3.2.0]
",org.apache.commons.collections.list;version="[3.0.0,3.2.0]
",org.apache.commons.collections.set;version="[3.0.0,3.2.0]
",org.apache.commons.logging

3.maven-bundle-plugin插件转换的Bundle

通常OSGi环境的开发相对比较复杂,从上面也可以看出对于Bundle的转换更加复杂,于是业界有提供这样的Maven插件maven-bundle-plugin(具体见参考资料[1])来做这个事情,所采用的转换方式正好是固定版本和非固定版本混合使用方式。

其实maven-bundle-plugin是使用bnd插件完成对Bundle的转换。这个Maven插件对于Bundle的转换主要使用asm解析,读取Jar文件中的class文件字节码信息,解析class文件中的package和import package信息,最后分析重写Manifest.MF的Import-Package和Export-Package。

这种模式在一个独立项目中使用,可能不会存在什么大问题,但是这个Maven插件转换后的Bundle无法很好处理几种特殊应用场景,下面从OSGi Bundle的2种依赖情况来详细分析下采用这种转换模式转换后的Bundle问题。

3.1转换为固定版本依赖

(图1)

如图1所示,假如是多人多部门协作开发的环境,那么就很有可能不同Bundle是由不同开发角色开发的,这时候BundleA1.0.0要求说必须使用BundleA1 1.0.1,BundleB 1.0.0要求说必须使用BundleA1 1.0.0。但是,他们所依赖的BundleA1的是冲突的,所以这时需要指定BundleA和BundleB依赖各自对应版本的BundleA1来解决,此时2个BundleA1同时在一个应用环境中存在并同时提供服务,固定版本方式的Bundle依赖很好解决了冲突问题。不过这种情况下,BundleA和BundleB同时存在会造成2个Bundle之间通信出现问题,这是由于同一个类(BundleA1中的类)进行类型转换时会因为classLoader不同而造成ClassCastException异常。在第4节“插件的改进”中将会详细描述如何解决固定版本模式出现的问题。

3.2 转换为非固定版本依赖

(图2)

在多人协作开发或者分布式应用环境中,如果BundleA和BundleB不指定依赖的BundleA1版本,那么在OSGi应用环境中,应用会使用verison>=0.0.0的方式选择Bundle,只要最新版本的Bundle可用,就会使用最新版本更新环境。如图2所示,BundleA 1.0.0 和BundleB 1.0.0均选择了最新版本的BundleA1 1.0.1安装,假如BundleA1提供了1.0.0和1.0.1,而且这2个版本是冲突的。BundleB 1.0.0会要求必须使用BundleA1 1.0.0,这时候的应用环境就成了图2这种情况,会造成最后安装的BundleA1环境不稳定,导致 BundleB 1.0.0功能出问题。反之,使用BundleA1 1.0.0,那么BundleA将会出现问题。 maven-bundle-plugin插件对于非遵守OSGi规范的Jar转换大多都会这种形式,因此在OSGi应用环境开发过程中尽量使用固定版本方式,虽然这种情况的开发相对困难些,但是改进好插件还是能够很好的帮助我们规避掉以后维护固定版本的工作量,而且能辅助我们很好的定位Bundle依赖出现的问题。

3.3插件的功能问题

如果要转换的Jar本身是OSGi Bundle,而且MANIFEST.MF的Import-Package中存在内容,原先Maven的maven-bundle-plugin插件则会继续使用该Import-Package。当然Import-Package的内容会遇到一些不规范的版本,特别是从未接触的开发人员,模仿着写,Import-Package写的有些问题,依赖信息错了,甚至由于开发人员疏忽写了些错误版本,这时候需要我们去修正为正确的信息,同理Export-Package也存在同样的问题。

另外MANIFEST.MF中没有Import-Package内容时:maven-bundle-plugin利用asm来解析*.class文件里import package来提取,提取方式如下所示:

(图3)

图3 BunldeA中只有这个类,那么BundleA的Import-Package为java.lang.reflect,org.objectweb.asm,com.wzucxd.classloader。

可以看出这种由maven-bundle-plugin插件转换的版本信息丢失很明显,再则由于bnd根据maven pom依赖进行转换,如果pom中有exclusions写法,那么当转换Bundle过程中,认为这个Bundle package依赖是不需要的,Import-Package会去除这个package,对于所依赖的Bundle来说可能会造成deploy失败。如BundleA1.0.0依赖的BundleA1 1.0.1需要com.wzucxd.classloader这个package,但是由于在BundleA1.0.0的pom中把BundleA1 1.0.1对应的com.wzucxd.classloader package exclusion出去了,而BundleA1.0.0的package中import进来,这种情况就有可能造成BundleA1 1.0.1 deploy失败了。

总之,maven-bundle-plugin插件转换后的Bundle,在应用运行过程中会存在的上述问题,故可以针对这几个改进措施来弥补插件的不足:

  1. 允许为所有package强制指定固定版本
  2. 修正OSGi Bundle Jar中不正确的Import-Package和Export-Package
  3. 解决exclusions等情况的版本丢失问题
  4. 解决可选版本问题,正确使用resolution:=optional

4.插件的改进

从Maven插件的不足中,我们也看到了核心问题在于该如何解决全部采用固定版本Bundle依赖时的转换问题。针对图1固定版本依赖这个问题,我们可以将冲突类放到bootdetegation中,但是这种解决方式不建议,这样做也就把这个类让WebAppClassLoder加载了,让应用方去解决maven冲突,所有Bundle中的这种冲突都会需要解决,显然这样不是一个好方式,这样就回到了原始社会。但是我们可以采用固定版本方式结合extra模式,这样可以很好的解决这个Bundle交互问题,将所有Bunlde做成固定版本的Import-Package到extra中,extra中指定的版本会用加载OSGi Framework的classloader加载,具体可以看下参考资料[2]里的内容,这种方式避免了大量使用bootdelegation来解决类型转换问题。

因此下面将具体介绍如何转换固定版本Import-Package和Export-Package的方法。

4.1 Export-Package转换

(图4)

从上面总结下来,对于Export-Package中的package版本修正,遇到没有使用版本或者错误信息的package时可以选择指定成当前转换Jar的pom version。

处理方法

转换过程可采用后序遍历方式逐级转换Jar,如图4所示,逐级转换asm-all,org.apache.felix.ipojo.metadata->org.apache.felix.ipojo。

  1. 将Jar中所有的package提取出来
  2. 继续把MANIFEST.MF中的Private-Package的package信息收集起来。

    另外在Bnd中,对应下面的代码可用来获取当前Jar的所有package,但是这个package是包含Private-Package的:

    (图5)

    最后将这些packages 减去Private-Package,并带有当前转换Jar的version的内容作为Export-Package。

  3. 解析当前Jar文件对应的pom文件,用pom version覆盖掉原先的version值,让所有Export-Package的version对应具体实际使用的版本。

    重新生成的Export-Package和MANIFEST.MF文件中原先的Export-Package数据这这个时候进行合并,于是最终对应的version值都会改成和该Jar对应的版本。

  4. 如griffin.core.module:1.0.5的Export-Package:

    (图6)

    处理后还存在无版本的package,则从Export-Package中去除,因为这种情况的package并不是他自己提供的,是由于原始的OSGi Bundle Jar写的不规范

uses语法的使用

转换后的Bundle在使用过程中,有时会遇到一个问题:interface类中使用了其他package的类,而这个interface类在实现类型的Bundle中却没有使用到。

如下图7和图8中的TemplateEngine interface(接口Bundle内)和HelloImpl类(实现Bundle内),在HelloImpl类中import了com.wzucxd.griffin.core.module.engine.TemplateEngine接口,但是不使用TemplateEngine接口。这时候实现的Bundle将会生成Export-Package:com.wzucxd.griffin.core.module.engine;uses:=com.wzucxd.griffin.core.module.context;version="1.0.5"

表示com.wzucxd.griffin.core.module.engine这个package要使用的时候,必须先install包含com.wzucxd.griffin.core.module.context package的Bundle;这样做的目的也是为了让Bundle依赖能够更加完整些。

(图7)

(图8)

4.2 Import-Package转换

对于Import-Package的转换要求更为严格,必须要在Export-Package转换后再进行转换,因为Import-Package的内容必须是被Export过的package。

转换方法:

使用4.1的方式转换好Export-Package

  1. 第1次后序遍历,转换时候先后序遍历转换所有的Jar,(maven dependency:tree可以参照maven的DependencyTreeBuilder实现);
  2. 转换Jar时,读取该Jar里所有java文件的字节码,分析class文件中的import内容,将所有import内容提取出来。并记录下所有依赖树里的package和Jar version信息,为V1<package,version> map集合。
  3. 在所有Jar转换完成后,将转换完成后的V1<package,version>与第1步Export-Package转换完成后记录的package version合并为V2<package,version>
  4. 第2次后序遍历,将Import-package的版本信息用第2步合并的V2<package,version>数据进行重写。这时候正常来说版本信息已经全部为固定版本信息。
resolution:=optional的使用:

第2次转换中会遇到一些异常情况,例如遇到原先没有版本,但是这个版本在maven仲裁中有定义,那么可使用maven仲裁的版本作为固定版本,这种情况需要加上resolution:=optional;转换时遇到maven仲裁后也无版本的,也就是说这个package无定义,在这个Bundle环境中是独立的,那么这个信息可能是Private-Package或者原先是OSGi Bundle中错误的Import,没有任何意义,这种Package去除掉,当然也可以使用resolution:=optional;表示这个package在install的时候是可选的,应用真正需要的时候再去install。

另外由于是根据pom转换Bundle,故遇到pom中含有这几种配置时也要用resolution:=optional:optional、exclude jar、exclude java类型的配置。因为在这几种情况下转换Bundle,是不可能知道使用的Import-Package版本,版本信息只有在maven仲裁后才知道(也有可能是开发者最后具体指定使用的版本),当前你也可以不写版本信息,但是这样不建议。resolution:=optional使用和Export-Package中的use有点类似,有些jar采用spi方式开发,只定义了接口,但是实现由具体的jar来做,实现的jar可以有多个,如common.logging,可以有多个log日志系统,那么这个接口使用必须都import进去,具体使用哪个由应用来决定。

例net.sf.json-lib_2.2.0的MANIFEST.MF

在这里可以看到org.apache.oro.text.regex;resolution:=optional;version="[0.0.0,0.0.0]",这里的resolution:=optional;用法表示这个package是非必须的依赖,可有也无,只有需要使用的时候才install,当应用中使用有export这个package的Bundle时,那么会提前install这个依赖Bundle,而且少这个package的时候也可以install net.sf.json-lib。

4.3 OSGi Bundle转换插件使用设计

这次我们从Convert插件使用上来看看,大多都会以什么习惯去使用Convert插件:

1.在pom中指定<packaging>bundle</packaging>

2.引入plugin(如图9)

(图9)

注:Instructions中可选属性有

  • Private-Package:将需要使用的package内容全部打包到Bundle中,私有package的内容由Bundle自身的classloader加载,但是不建议使用,容易出现被指定的package在WebAppClassloader加载过
  • Import-Package:指定bundle的import,import如果写明具体版本,格式为<Import-Package> xxx.xxx.xxx;version="[1.0.0,1.0.0]", xxx.xxx.xxx;version="[xxx,xxx]"</Import-Package>,将这个Import-Package信息覆盖bnd插件转换后的Import-Package
  • Export-Package:对外暴露的package,可被其他bundle import使用,Export-Package的所有package必须带版本,而且建议和pom的版本一致,版本也可以自己指定
  • Ignore-Package:这里的Ignore-Package作用:转换的时候过滤掉这些package信息,在所有Bundle转换之前,可以提前配置了一个bnd.properties文件,里面指定所有Import-Package不需要import的package,里面的内容基本为jdk里的package,因为jdk刚开始由WebAppClassLoader加载, 当然可以为每个Bundle默认写上Ignore-Package。
  • Bundle-SymbolicName:Bundle的名字,建议用${project.groupId}+${project.artifactId}的组合
  • Interface类型的Bundle在开发过程一般只写Export-Package就好,如果接口Bundle作为二方库方式开发也可以,在Bundle.implement中引用接口pom的时候,插件在转换Bundle.implement之前转换对接口做Bundle Convert,为接口Bundle中的MANIFEST.MF写入正确的Import-Package和Export-Package信息。
  • Bundle.implement作为实现Bundle,一般不需要写Export-package/Import-Package,一些特殊的Bundle,如这个Bundle.implement实现使用了动态代理的service,那么大多可以在Import-Package中指定这个service interface的package来解决。

插件编译参数设计,为了提升效率,必要的编译参数也是需要的:

插件编译参数设计,为了提升效率,必要的编译参数也是需要的:
//编译前是否清理缓存目录
maven install -Dbundle.clean=true/(false)
//是否编译snapshot
maven install -Dsnapshot.rebuild=(true)/false
//只编译指定的bundle
maven install -D buildBundle=com.common.util

这样对Bundle的Import-Package和Export-Package可以进行一定程度的自定义了,但是我们还是更希望尽量一次性完整的转换好Bundle,用插件来完全负责转换Import-Package和Export-Package。

4.4 MANIFEST.MF中其他信息的定义

Bundle-Convert:表示从普通Jar转为OSGi Bundle后的表示

Bundle-Build:表示原先是标准的OSGi Bundle,如自己开发的标准Bundle.implement

Bundle-Sha1:表示这个Bundle的唯一版本信息,计算方式:BundleConvertUtil.getSha1(File file);具体sha1或者md5计算方法很多,这里的具体作用还为了以后将转换后的Bundle保存到一个组件仓库中避免重复Bundle的多次转换,也可以用来区分一个Bundle是否被多次编译。

5.总结

改进后的Convert插件也还存在一个问题,pom转换为OSGi Bundle时出现的Jar版本冲突,允许2个版本都可以使用,这里的方法是使用自己解决冲突的方式,插件转换时用了maven仲裁的版本。这里的版本就相当坑,maven使用树状最短路径版本,而OSGi Bundle使用的是图状关联版本,故这个时候使用多个版本的OSGi Bundle会使用version="[xxx,xxx]"区间值表达,但是在我们这里还是建议使用maven仲裁选择一个固定版本。当然固定版本选择是为了支持extra使用,所以在这个插件使用的时候,不建议应用方在pom中的Jar依赖与接口Bundle的pom依赖有冲突,冲突需要应用方提前先解决,当然这个做法也是合理的,因为应用新引入一个接口Jar的时候,pom依赖有冲突那么需要提前解决。在插件中也可以在转换过程中就将有冲突的Package提前抛出异常告知开发者,在编译期就让开发者解决掉这个问题。

6.参考资料

[1] apache-felix-maven-bundle-plugin-bnd插件 http://felix.apache.org/site/apache-felix-maven-bundle-plugin-bnd.html

[2]Exposing the boot classpath in OSGi http://spring.io/blog/2009/01/19/exposing-the-boot-classpath-in-osgi/

作者简介

陈旭东,阿里巴巴资深研发工程师,主导过阿里巴巴地图的架构设计,对搜索规则和旺铺SEO优化有非常全面资深的了解。目前主导搜索应用的架构设计和搜索应用Osgi框架研发。


感谢张龙对本文的审校。

给InfoQ中文站投稿或者参与内容翻译工作,请邮件至editors@cn.infoq.com。也欢迎大家通过新浪微博(@InfoQ)或者腾讯微博(@InfoQ)关注我们,并与我们的编辑和其他读者朋友交流。

评价本文

专业度
风格

您好,朋友!

您需要 注册一个InfoQ账号 或者 才能进行评论。在您完成注册后还需要进行一些设置。

获得来自InfoQ的更多体验。

告诉我们您的想法

允许的HTML标签: a,b,br,blockquote,i,li,pre,u,ul,p

当有人回复此评论时请E-mail通知我

非常实用,谢谢! by 孙 奇辉

看来阿里巴巴在使用OSGi方面是比较深入的,也在关键产品中使用了。但好像也有人说在去OSGi,是怎么个情况呢?

Re: 非常实用,谢谢! by 陈 旭东

强制要求所有同学使用OSGi,必然会产生抵触心理,因为OSGi Bundle的开发成本相对会高些。内部对此做很多事情来提升Bundle开发效率,开发框架封装好,使用性提升后问题就不会太大;很多需求其实是希望非OSGi应用使用Bundle,通过spring与隔离的osgi container来交互,这样对于普通开发同学来说使用Bundle也没有什么学习成本,当真需要把功能服务化出去的时候才需要开发Bundle。降低OSGi的开发复杂性,内部还是在使用的,所以搜索应用这边主要针对非OSGi环境下使用Bundle,不强制要求业务方必须使用,而是把服务性质的功能OSGi化,目前环境也已经改造的比较符合现有的开发习惯,而且搜索服务化确实比较适合用OSGi,现在也一直运行中。

Re: 非常实用,谢谢! by 孙 奇辉

infoq,不能删除多余的回复!

Re: 非常实用,谢谢! by 孙 奇辉

强制要求所有同学使用?在你的搜索部门吗?还是所有的阿里平台开发部?
什么时候搞搞讲座或者沙龙分享下你们的经验?

Re: 非常实用,谢谢! by 孙 奇辉

infoq,不能删除多余的回复!

Re: 非常实用,谢谢! by 陈 旭东

支付宝那边的应用环境是osgi,要求web应用也必须是OSGi,故在Bundle通信的时候,业务Bundle处理时Bundle通信会比较复杂,整个历史环境在那了,也已经支撑了大部分业务,底层上做变动可能性很小了,所以支付宝那边新来的同学都必须学些osgi相关的,在支付宝对此也开发了OSGi的开发框架来降低新人的入门门槛;而我们搜索这边这次采用全新的设计,在技术底层上直接就设计成允许非OSGi应用使用,具有更好的易用性,不改变开发习惯为原则,待这边使用更加成熟后,也将会选择把开发框架和OSGi容器开源。
有合适的时间,我们也可以组织做个分享,关于我们目前的框架研发情况。

Re: 非常实用,谢谢! by 孙 奇辉

Good ,确实每个追求模块化的工程师都应该学习下OSGi! 你们用了哪些OSGi框架,是Apache Karaf、Aries还是Eclipse Virgo/Gemini? 我希望即将发布的OSGi R6,在企业级规范上能有极大突破!

Re: 非常实用,谢谢! by 陈 旭东

支付宝这边选择了equinox,在这方面我们综合考虑使用了felix,主要是felix的子项目ipojo\OSGi Bundle Repository\gogo,另外felix还提供了很多协助排查问题的工具,在felix上实现一个轻量的OSGi容器,用于Bundle的运行环境支持;结合插件还可以做很多扩展,spring dm/blueprint与obr的整合等,而且扩展也相对比较容易。我也相信OSGi会越来越好。

Re: 非常实用,谢谢! by 陈 旭东

支付宝这边选择了equinox,在这方面我们综合考虑使用了felix,主要是felix的子项目ipojo\OSGi Bundle Repository\gogo,另外felix还提供了很多协助排查问题的工具,在felix上实现一个轻量的OSGi容器,用于Bundle的运行环境支持;结合插件还可以做很多扩展,spring dm/blueprint与obr的整合等,而且扩展也相对比较容易。我也相信OSGi会越来越好。

Re: 非常实用,谢谢! by 孙 奇辉

“所以搜索应用这边主要针对非OSGi环境下使用Bundle,不强制要求业务方必须使用,而是把服务性质的功能OSGi化” --我的理解是,你们是做开发框架和容器及搜索业务的平台部门,提供一些搜索公共的能力和服务,这些基本是以OSGi的bundle形式提供的。而业务方要求调用你们的bundle,最大的挑战可能是要面对的这些bundle是动态的:可能随时安装和卸载、启动和停止 ,而业务方不一定运行在一个OSGi框架中,业务方如何处理这种挑战?值得探索。

Re: 非常实用,谢谢! by 陈 旭东

业务方以服务的方式使用,对业务方来说只需要指明<griffin:bean id="xxx" instanceName="xxx"/>类似于这样的标签,表明需要使用哪个service即可,就像dubbo一样,在需要使用dubbo服务的使用启动dubbo环境,业务方不会感知到有osgi的存在。
具体这个service在哪个bundle中,则会通过启动后的osgi容器去obr仓库中查询对应的Bundle,然后动态安装到业务方的osgi容器中;而对于业务方来说几乎不会感知有bundle的存在,只关注调用service即可;业务方的应用都会自动注册到一个统一的管理中心,这里通过消息机制,有bundle更新操作,则通知所有使用osgi框架的应用是否需要更新行为;bundle开发者的应用启动后会自动与obr仓库比对,自动上传并检测bundle完整性进行更新。这里涉及的组件与osgi容器的交互机制有些复杂,没法很好讲清楚。:)

Re: 非常实用,谢谢! by 孙 奇辉

“然后动态安装到业务方的osgi容器中” -- 这个是指业务方的osgi容器是用来安装运行服务提供者的bundle的。而为作服务消费者,业务本身的代码可以是普通Java EE编程模型,而不需要封装为bundle吧。

Re: 非常实用,谢谢! by 陈 旭东

是的,这样的模式对业务方有利,更容易被业务方所接受。

Re: 非常实用,谢谢! by 孙 奇辉

还有个疑问,你提到的依赖版本很固定,只写一个版本,例如是[1.0.4,1.0.4]、[1.8.3,1.8.3],而许多著作中推荐的是一个区间,例如[1.0.4,2)、[1.8.3,2),即采用OSGi的Semantic Versioning。为何这么做?

Re: 非常实用,谢谢! by 陈 旭东

如果业务应用调用的service关联了2个Bunlde,Bundle1和Bundle2分别依赖1.0.4,1.0.5,但是这2个版本是不能共存的,这时候有不熟悉的开发人员开发了不兼容业务内部逻辑的1.0.5,Bundle1使用[1.0.4,2),那么将会导致Bunlde1业务功能出现问题,这时候还得需要升级Bundle1才能解决,在实际应用也确实出现了这种情况,公司的maven仓库中有不少区间写法的Bundle依赖存在这种问题,环境复杂了,区间方式在依赖管理中也非常不便;因此采用pom结构中的所有依赖,直接仲裁成具体的版本,那么这个环境是稳定的,并且没有snapshot,一旦有什么升级不会直接影响到历史Bundle,也避免一些误升级;

Re: 非常实用,谢谢! by 孙 奇辉

好,谢谢,可能需要画些图示才能更加明白这种情况。
我也是很看好OSGi,即使预计在Java 9中将加入的Jigsaw项目,也逃不脱OSGi历经15年遇到的各种挑战和解决方案。很可能只是OSGi的一个功能子集,并且会保持兼容。Jigsaw即使不再延期,真正采用也得4-5年了。

是否可以提供源码 我这边项目正在使用 第三方jar迁移时发现比较复杂。 by 高 进

是否可以提供源码 我这边项目正在使用 第三方jar迁移时发现比较复杂。

最好把通过反射加载的class类型以及自定义类加载加载方式,也一起讲下,一些实践总结。 by 高 进

最好把通过反射加载的类型以及自定义类加载加载方式,业务讲下,一些实践总结。

OSGI 成果 by soft wmz

osgi.jxtech.net 就是一个成熟的基于OSGi的开发平台,有在线演示,并且还有一些公用的功能插件可免费下载。

OSGI 成果 by soft wmz

osgi.jxtech.net 就是一个成熟的基于OSGi的开发平台,有在线演示,并且还有一些公用的功能插件可免费下载。

允许的HTML标签: a,b,br,blockquote,i,li,pre,u,ul,p

当有人回复此评论时请E-mail通知我

允许的HTML标签: a,b,br,blockquote,i,li,pre,u,ul,p

当有人回复此评论时请E-mail通知我

20 讨论

登陆InfoQ,与你最关心的话题互动。


找回密码....

Follow

关注你最喜爱的话题和作者

快速浏览网站内你所感兴趣话题的精选内容。

Like

内容自由定制

选择想要阅读的主题和喜爱的作者定制自己的新闻源。

Notifications

获取更新

设置通知机制以获取内容更新对您而言是否重要

BT