0
OSGi理论和实战<br />BlueDavy<br />http://china.osgiusers.org<br />09.09.15<br />
目标<br />学习OSGi规范 R4.1,掌握OSGi核心概念;<br />学习OSGi R4实现框架的实现机制,以更好的使用这些框架;<br />学习基于Equinox开发OSGi Based的应用;<br />扩展Equinox,更好的基...
大纲<br />OSGi介绍 <br />OSGi实现框架<br />扩展Equinox<br />Equinox高级实战<br />分布式OSGi<br />
1、OSGi介绍<br />在OSGi中,模块是什么?<br />模块之间的类是如何做到隔离的?<br />怎么访问其他模块中的类?<br />模块的生命周期是怎么样的?<br />模块之间怎么交互?<br />OSGi提供了哪些常用的Serv...
我期望的模块化、动态化<br />模块化(Java 7中最重要的Feature)<br />独立,不受其他模块的影响;<br />其他模块只能访问该模块对外提供的功能;<br />模块具备独立的生命周期,例如启动、停止、更新等。<br />动态...
OSGi是什么<br />一个标准,基于此标准实现的框架可轻松的构建模块化、动态化的系统;<br />Dynamic Module System For Java;<br />JSR 232、JSR 291;<br />众多Java Appli...
Bundle<br />Bundle是OSGi中部署的最小单位,因此可以认为Bundle就是模块;<br />Bundle就是一个普通的jar包,只是其在MANIFEST.MF中加入了一些特殊的头信息,例如Bundle-Name;<br />
Bundle类隔离机制<br />Java ClassLoader机制<br />类由ClassLoader来实现加载,Java动态化实现的基础;<br />默认情况下有BootStrapClassLoader(jre/lib、jre/clas...
Bundle类隔离机制<br />每个Bundle均为独立的ClassLoader,典型的Bundle的ClassLoader结构如下所示:<br />
Bundle类共享机制<br />Java经典的Delegation模型<br />在寻找类时首先从parent classloader中寻找,如找不到才在当前classloader中寻找;<br />
Bundle类共享机制<br />Bundle类加载过程<br />java.*委派给parent classloader加载;<br />bootdelegation参数中配置的也委派给parent classloader加载,在parent...
Bundle类共享机制<br />因此可以通过在MANIFEST.MF中定义Require-Bundle、Import-Package、Export-Package以及DynamicImport-Package来实现类共享;<br />Impo...
Bundle类共享机制<br />Import-Package寻找机制<br />比较提供了相应package的Bundle的状态,resolved优先于未resolved的;<br />如均为resolved的bundle,则比较packag...
Bundle生命周期<br />OSGi按照下面的状态转换方式来管理Bundle的生命周期;<br />可通过OSGi提供的API来主动改变Bundle的生命周期。<br />BundleContext.installBundle<br />B...
Bundle生命周期<br />Install Bundle时要做的事情<br />解析Bundle的MANIFEST.MF信息,判断格式是否符合标准以及是否存在相同的Bundle;<br />分配新的Bundle ID后;<br />生成Bu...
Bundle生命周期<br />Resolve Bundle时要做的事情<br />寻找Bundle中所需依赖的包或Bundle是否存在以及被resolve,包括寻找匹配的import-package、require-bundle等,如寻找到则...
Bundle生命周期<br />Start Bundle时要做的事情<br />检查Bundle的状态,如未Resolve,则先Resolve;<br />寻找MANIFEST.MF中配置的Bundle-Activator,如寻找到,则调用其s...
Bundle生命周期<br />Stop Bundle时要做的事情<br />卸载当前Bundle对外提供的所有OSGi Service,并释放当前Bundle引用的所有OSGi Service;<br />调用MANIFEST.MF中对应的B...
Bundle生命周期<br />Uninstall Bundle时要做的事情<br />检查Bundle状态,如状态为ACTIVE,则先STOP;<br />释放Bundle对其他Bundle的类依赖;<br />如当前Bundle中有其他Bu...
Bundle生命周期<br />Update Bundle时要做的事情<br />首先停止当前Bundle;<br />重新安装并RESOLVE Bundle;<br />恢复到Bundle更新之前的状态。<br />
Bundle生命周期总结<br />除了DynamicImport-Package外,其他的Package引用哪个Bundle在Resolve时就已经决定了;<br />如希望更新Bundle所引用到的类,则必须进行refresh动作;<br ...
Bundle交互<br />Service<br />registry<br />packages<br />packages<br />直接类访问的方式(不推荐),结合上面之前的Bundle生命周期的介绍,为什么?;<br />Service...
Bundle交互<br />Declarative Services(简称DS)<br />Service-Oriented Component Model<br />需要对外提供的功能均定义为接口;<br />接口的实现定义以XML方式定义为...
Bundle交互<br />对外提供服务示例<br />调用其他Bundle的服务示例<br />
Bundle交互<br />提供服务关键配置<br />provide interface,声明对外提供的接口;<br />property,可增加一些服务实现的关键词,以便匹配过滤,例如&lt;property  name=“KEY” val...
Bundle交互<br />DS 1.1的可喜变化<br />Service-Component后指定的文件可用通配符,例如:Service-Component: OSGi-INF/*.xml<br />可以配置activate和deactiv...
Bundle交互<br />Component生命周期<br />如Component有对外提供服务,在没有其他Component需要此服务时,这个Component是不会被激活的,只有当有其他Component需要此服务,且当前Compone...
Bundle交互<br />Component生命周期<br />当有Bundle启动时,会触发Declarative services的介入,以将其中的Service-Component对应的配置文件的Component载入;<br />当有...
R 4.2将会带来的变化<br />Launch Framework API<br />这个API的引入就意味着以后可以以一种统一的方式在程序中启动OSGi Framework了,示例如下:<br />	Map p=new HashMap();...
OSGi提供的服务<br />Http Service<br />以便支持简单的通过http访问OSGi应用;<br />但复杂的场景还是比较难支撑,这主要是由于目前还只有jetty实现的HttpService,再加上它所支持的Servlet版...
OSGi对模块化、动态化的满足程度<br />模块化<br />完全满足。<br />动态化<br />能够动态的增加、删除或更新模块,并完成依赖的OSGi Service的引用迁移;<br />但要自行处理由此带来的模块中对象的状态保持和恢复...
2、OSGi实现框架<br />有哪些实现框架?<br />它们是如何实现OSGi规范的?<br />它们是否遵循OSGi标准?<br />对比而言,谁更有优势?<br />
OSGi实现框架<br />Equinox<br />Equinox是R 4.0的RI,并且也是Eclipse的核心,可谓是久经考验,Spring-DM也是基于Equinox。<br />Felix<br />Felix作为后起之秀,表现算得上...
OSGi实现框架<br />Equinox<br />Equinox的ClassLoader结构<br />
OSGi实现框架<br />Equinox中的类加载顺序<br />根据启动时的bootdelegation属性判断是否需要从parent classloader中加载,具体parent classloader是哪个,则可以通过osgi.par...
OSGi实现框架<br />Equinox<br />Install Bundle<br />按照提供的Bundle文件加载流,并根据MANIFEST.MF的信息形成Bundle对象,并将Bundle的状态置为INSTALLED;<br />对...
OSGi实现框架<br />Equinox<br />Resolve Bundle<br />如bundle为singleton,则首先检查singletons bundle是否已存在,如存在则resolve失败;<br />对所依赖的pack...
OSGi实现框架<br />Equinox<br />Start Bundle<br />检查状态是否为RESOLVED,如未resolve则先进行resolve动作,resolve失败则直接抛出异常,成功则继续下面步骤;<br />调用MAN...
OSGi实现框架<br />Equinox<br />Stop Bundle<br />注销发布的OSGi服务以及释放对其他OSGi服务的引用;<br />调用MANIFEST.MF中配置的bundle-activator的类的stop方法;<...
OSGi实现框架<br />Equinox<br />Uninstall Bundle<br />如Bundle为Active,先停止Bundle;<br />检查是否有其他Bundle依赖了当前Bundle的package,如有则先不关闭此b...
OSGi实现框架<br />Equinox<br />Update Bundle<br />如状态为ACTIVE,先停止;<br />创建新的Bundle对象,如有Bundle依赖老版本的Bundle,则暂时将老版本的Bundle放入remov...
OSGi实现框架<br />Refresh<br />找到所有removalPendings中的bundle,unresolve这些bundle,并重新resolve依赖了这些bundle的bundle;<br />恢复重新resolve了的b...
OSGi实现框架<br />Equinox<br />DS在这些过程中的处理<br />Start Bundle时<br />扫描MANIFEST.MF中对应的Service-Component指定的文件,加载这些文件;<br />判断其中指定...
OSGi实现框架<br />Felix<br />Felix的ClassLoader结构<br />
OSGi实现框架<br />Felix中的类加载顺序<br />判断是否为bootdelegation中配置的package,如交由Felix ClassLoader进行加载;<br />尝试从Import-Package中加载,如在则交由相应...
OSGi实现框架<br />Felix<br />Install Bundle<br />解析Bundle的MANIFEST.MF文件,读取OSGi标准中定义的头信息;<br />检查Bundle的唯一性,如不唯一则抛出异常;<br />将Bu...
OSGi实现框架<br />Felix<br />Resolve Bundle<br />寻找需要依赖的Package或Bundle,并将其中未resolve的Bundle进行resolve,如resolve失败,则将其从潜在的Bundle列表...
OSGi实现框架<br />Felix<br />Start Bundle<br />检查Bundle状态,如未resolve则先resolve;<br />执行MANIFEST.MF中对应的Bundle-Activator配置的类的start...
OSGi实现框架<br />Felix<br />Stop Bundle<br />执行MANIFEST.MF中对应的Bundle-Activator配置的类的stop方法,如未配置则跳过此步;<br />注销Bundle对外发布的Servic...
OSGi实现框架<br />Felix<br />Uninstall Bundle<br />检查状态,如为ACTIVE,则先停止;<br />如有其他Bundle引用了当前Bundle的package,则将当前Bundle的RemovalPe...
OSGi实现框架<br />Felix<br />Update Bundle<br />停止当前的Bundle;<br />重新读取并解析Bundle流,将Bundle状态置为INSTALLED;<br />恢复Bundle到更新前的状态。<b...
OSGi实现框架<br />Felix<br />Refresh<br />在指定Bundle的情况下,递归找到依赖当前Bundle提供的package的Bundle,作为此次refresh动作需要操作的Bundles;在未指定Bundle的情...
OSGi实现框架<br />Felix<br />DS在这些过程中的处理<br />和Equinox基本一致;<br />但值得注意的是Felix DS 1.0.8对于policy=dynamic、cardinality=“0..1” | “0...
OSGi实现框架对比<br />
3、扩展Equinox<br />如何在外部程序中启动Equinox?<br />是否可以对Equinox进行扩展?<br />如可以扩展,应如何做?<br />
扩展Equinox<br />在外部程序中启动Equinox<br />示例<br /> 	// 配置Equinox的启动<br />FrameworkProperties.setProperty(&quot;osgi.noShutdown&q...
扩展Equinox<br />Equinox中可用的扩展<br />ClassLoadingHook<br />ClassLoaderDelegateHook<br />ClassLoadingStatsHook<br />AdaptorHoo...
扩展Equinox<br />ClassLoadingHook<br />可用于拦截Bundle ClassLoader的创建、类的处理、Classpath的处理等;<br /><ul><li>ClassLoaderDelegateHook
可用于在某个阶段干预类的加载,例如在类从Import-Package中扫描之前或在DynamicImport-Package扫描之后。</li></li></ul><li>扩展Equinox<br /><ul><li>ClassLoadingS...
可用于拦截类从Bundle-Classpath中加载的动作,包括加载之前以及加载之后。</li></ul>AdaptorHook<br />可用于拦截BaseAdaptor的创建过程,例如在初始化时、framework启动时、停止时。<br />
扩展Equinox<br />注册Hook类的方法<br />属性中指定<br />在启动时指定osgi.hook.configurators,但要注意的是要加上目前Equinox所需的hooks配置,格式为:<br />hook.config...
Equinox扩展的启示<br />框架级的软件都应提供良好的扩展支持,方式可以为:<br />Filter<br />可通过扩展OSGiService模型来实现;<br />适合组装为一连串的处理来完成一个功能。<br />Intercept...
4、Equinox高级实战<br />将上节的东西应用到实战中!<br />如何控制Equinox的ClassLoader?<br />如何将非DS的应用迁移为DS方式?<br />如何应对采用OSGi后一些常见的错误?<br />
Equinox高级实战<br />控制Equinox的ClassLoader<br />基于ClassLoaderDelegateHook实现<br />实现ClassLoaderDelegateHook以及HookConfigurator接口...
Equinox高级实战<br />将非DS的应用迁移为DS方式<br />迁移的方法<br />将之前直接类的调用方式改为基于接口的方式,这也将对动态化的实现更为有利;<br />将接口放入一个独立的Bundle中,也是为了动态化;<br />...
Equinox高级实战<br />将非DS的应用迁移为DS方式<br />示例<br />迁移好处<br />解放之前对于BundleContext.registerService等这些难用的用法;<br />避免需要自己基于ServiceTr...
Equinox高级实战<br />将非DS的应用迁移为DS方式<br />DS的四种经典用法<br />set注入单个依赖的服务;<br />&lt;reference name=… interface=… bind=… unbind=… po...
Equinox高级实战<br />经常会碰到的一些问题<br />ClassNotFoundException<br />几乎是所有使用OSGi的人都会经常碰到的问题;<br />解决的方法是掌握Bundle Class的加载方式;<br />...
5、分布式OSGi<br />有哪些实现框架?<br />它们是如何实现的?<br />对比而言,谁更有优势?<br />
分布式OSGi<br />你所期望的?<br />我所期望的<br />透明的将OSGi服务发布为可远程调用的服务;<br />透明的调用远程的OSGi服务;<br />OSGi服务的动态化感知不是必须的<br />由于这受限于网络等各种因素,...
分布式OSGi<br />Java远程通信<br />(TCP/IP、UDP/IP、多播)+NIO/BIO<br />Java远程RPC<br />RMI:基于代理、反射机制<br />Webservice:基于http RPC机制<br />
分布式OSGi<br />分布式OSGi<br />R-OSGi<br />老牌,有一定的优势,但用户群不多;<br />CXF DOSGi<br />作为将来的R 4.2的RFC119的实现,值得期待!<br />
分布式OSGi<br />R-OSGi<br />能达到的效果<br />透明的将OSGi Service对外发布;<br />只需要在注册OSGi Service时加上properties.put(RemoteOSGiService.R_OS...
分布式OSGi<br />R-OSGi<br />实现机制<br />监听了服务注册事件,当有服务注册时,检查其注册的属性,如属性中有RemoteOSGiService.R_OSGi_REGISTRATION,并且值为true,那么则做一个服务...
分布式OSGi<br />CXF DOSGi<br />能达到的效果<br />透明的将OSGi Service对外发布;<br />只需在注册服务时增加如下属性即可:<br />props.put(&quot;osgi.remote.inte...
分布式OSGi<br />CXF DOSGi<br />实现机制<br />监听服务注册事件,当注册时有相应的属性时,则将其发布为Webservice;<br />对于客户端,则通过扫描相应的service-description的描述来生成一...
分布式OSGi<br />个人的经验<br />分布式OSGi的实现多数和OSGi并没有多大的关系,其核心原理均为实现一个透明的远程RPC;<br />如需关注性能、稳定性来说完全可以自行实现;<br />所需的知识为代理、反射、网络通信以及服...
Upcoming SlideShare
Loading in...5
×

OSGi理论与实战

3,414

Published on

和清华学子交流的一个OSGi PPT。

Published in: Technology, Education
1 Comment
11 Likes
Statistics
Notes
No Downloads
Views
Total Views
3,414
On Slideshare
0
From Embeds
0
Number of Embeds
2
Actions
Shares
0
Downloads
282
Comments
1
Likes
11
Embeds 0
No embeds

No notes for slide

Transcript of "OSGi理论与实战"

  1. 1. OSGi理论和实战<br />BlueDavy<br />http://china.osgiusers.org<br />09.09.15<br />
  2. 2. 目标<br />学习OSGi规范 R4.1,掌握OSGi核心概念;<br />学习OSGi R4实现框架的实现机制,以更好的使用这些框架;<br />学习基于Equinox开发OSGi Based的应用;<br />扩展Equinox,更好的基于Equinox来开发各类应用;<br />学习分布式OSGi;<br />
  3. 3. 大纲<br />OSGi介绍 <br />OSGi实现框架<br />扩展Equinox<br />Equinox高级实战<br />分布式OSGi<br />
  4. 4. 1、OSGi介绍<br />在OSGi中,模块是什么?<br />模块之间的类是如何做到隔离的?<br />怎么访问其他模块中的类?<br />模块的生命周期是怎么样的?<br />模块之间怎么交互?<br />OSGi提供了哪些常用的Service?<br />
  5. 5. 我期望的模块化、动态化<br />模块化(Java 7中最重要的Feature)<br />独立,不受其他模块的影响;<br />其他模块只能访问该模块对外提供的功能;<br />模块具备独立的生命周期,例如启动、停止、更新等。<br />动态化<br />能动态的增加、更新或删除模块,而对于模块来说不需要做额外的处理;<br />你期望中的?<br />
  6. 6. OSGi是什么<br />一个标准,基于此标准实现的框架可轻松的构建模块化、动态化的系统;<br />Dynamic Module System For Java;<br />JSR 232、JSR 291;<br />众多Java Application Server(Weblogic、Glassfish等)所选择的底层框架;<br />
  7. 7. Bundle<br />Bundle是OSGi中部署的最小单位,因此可以认为Bundle就是模块;<br />Bundle就是一个普通的jar包,只是其在MANIFEST.MF中加入了一些特殊的头信息,例如Bundle-Name;<br />
  8. 8. Bundle类隔离机制<br />Java ClassLoader机制<br />类由ClassLoader来实现加载,Java动态化实现的基础;<br />默认情况下有BootStrapClassLoader(jre/lib、jre/classes)、Extension ClassLoader(jre/lib/ext)以及System ClassLoader(-classpath指定)三个级别的ClassLoader;<br />应用可自行实现ClassLoader以动态的加载类,或加载相应目录下的类;<br />
  9. 9. Bundle类隔离机制<br />每个Bundle均为独立的ClassLoader,典型的Bundle的ClassLoader结构如下所示:<br />
  10. 10. Bundle类共享机制<br />Java经典的Delegation模型<br />在寻找类时首先从parent classloader中寻找,如找不到才在当前classloader中寻找;<br />
  11. 11. Bundle类共享机制<br />Bundle类加载过程<br />java.*委派给parent classloader加载;<br />bootdelegation参数中配置的也委派给parent classloader加载,在parent classloader中未找到也继续下面的步骤;<br />是否在Import-Package中,在则委派给Export-Package的bundle的classloader;<br />是否在Require-Bundle中,在则委派给相应的Bundle ClassLoader,未找到则继续下面步骤;<br />在Bundle-Classpath中寻找,未找到则继续下面的步骤;<br />在fragments bundle的classpath中寻找,未找到则继续下面的步骤;<br />是否在Export-Package中,未找到则继续下面的步骤;<br />是否在DynamicImport-Package中,在则委派给相应的Bundle ClassLoader寻找,不在则抛出ClassNotFound异常。<br />
  12. 12. Bundle类共享机制<br />因此可以通过在MANIFEST.MF中定义Require-Bundle、Import-Package、Export-Package以及DynamicImport-Package来实现类共享;<br />Import-Package: org.osgiusers.china.demo<br />Export-Package: org.osgiusers.china.demo<br />DynamicImport-Package: org.osgiusers.*<br />注意:OSGi支持包的版本的定义!<br />Import-Package: org.osgiusers.china.demo;version=“[1.0,2.0)”<br />
  13. 13. Bundle类共享机制<br />Import-Package寻找机制<br />比较提供了相应package的Bundle的状态,resolved优先于未resolved的;<br />如均为resolved的bundle,则比较package的版本,默认package版本为0.0.0,版本高的优先于版本低的;<br />如版本也一样,则比较bundle id,bundle id小的优先于大的,也就是先安装的bundle优先。<br />
  14. 14. Bundle生命周期<br />OSGi按照下面的状态转换方式来管理Bundle的生命周期;<br />可通过OSGi提供的API来主动改变Bundle的生命周期。<br />BundleContext.installBundle<br />Bundle.start<br />Bundle.update<br />Bundle.stop<br />Bundle.uninstall<br />Bundle生命周期改变时所做的动作将直接影响动态化。<br />INSTALLED<br />STARTING<br />start<br />RESOLVED<br />ACTIVE<br />stop<br />UNINSTALLED<br />STOPPING<br />
  15. 15. Bundle生命周期<br />Install Bundle时要做的事情<br />解析Bundle的MANIFEST.MF信息,判断格式是否符合标准以及是否存在相同的Bundle;<br />分配新的Bundle ID后;<br />生成Bundle对象,并放入已安装的Bundles集合中,状态置为INSTALLED。 <br />
  16. 16. Bundle生命周期<br />Resolve Bundle时要做的事情<br />寻找Bundle中所需依赖的包或Bundle是否存在以及被resolve,包括寻找匹配的import-package、require-bundle等,如寻找到则进入检查,检查完冲突后形成绑定关系,以便加载类时能直接加载;<br />冲突示例<br />A Bundle依赖org.osgiusers.china.demo;version=1.0.0,org.osgiusers.china.user;version=2.0.0;<br />B Bundle提供了org.osgiusers.china.demo;version=1.0.0,但同时import了org.osgiusers.china.user;version=1.1.0<br />如成功,则将Bundle状态置为RESOLVED。<br />
  17. 17. Bundle生命周期<br />Start Bundle时要做的事情<br />检查Bundle的状态,如未Resolve,则先Resolve;<br />寻找MANIFEST.MF中配置的Bundle-Activator,如寻找到,则调用其start方法;<br />将Bundle状态标识为ACTIVE。<br />
  18. 18. Bundle生命周期<br />Stop Bundle时要做的事情<br />卸载当前Bundle对外提供的所有OSGi Service,并释放当前Bundle引用的所有OSGi Service;<br />调用MANIFEST.MF中对应的Bundle-Activator的类的stop方法;<br />将Bundle状态置为RESOLVED。<br />
  19. 19. Bundle生命周期<br />Uninstall Bundle时要做的事情<br />检查Bundle状态,如状态为ACTIVE,则先STOP;<br />释放Bundle对其他Bundle的类依赖;<br />如当前Bundle中有其他Bundle的类依赖,则进行记录,如没有则释放该Bundle的ClassLoader;<br />将当前Bundle的状态置为UNINSTALLED。<br />
  20. 20. Bundle生命周期<br />Update Bundle时要做的事情<br />首先停止当前Bundle;<br />重新安装并RESOLVE Bundle;<br />恢复到Bundle更新之前的状态。<br />
  21. 21. Bundle生命周期总结<br />除了DynamicImport-Package外,其他的Package引用哪个Bundle在Resolve时就已经决定了;<br />如希望更新Bundle所引用到的类,则必须进行refresh动作;<br />但refresh动作也只对目前处于unresolve状态的以及之前uninstall时还有其他bundle类依赖的Bundle进行unresolve动作,并重新resolve对他们有依赖的bundle。<br />从上可见,当Bundle有Start动作时,有可能会造成有Bundle的ClassLoader建立成功,当发生Refresh动作时,有可能会造成某些Bundle Resolve失败,也有可能造成某些Bundle重建ClassLoader。<br />
  22. 22. Bundle交互<br />Service<br />registry<br />packages<br />packages<br />直接类访问的方式(不推荐),结合上面之前的Bundle生命周期的介绍,为什么?;<br />Service交互方式<br />直接通过BundleContext.getServiceReference以及BundleContext.registerService这样的方式(使用不方便,不推荐);<br />Declarative Services方式,类似IoC type 2;<br />OSGi Framework<br />Bundle<br />Bundle<br />JAVA<br />Operating System<br />Hardware<br />
  23. 23. Bundle交互<br />Declarative Services(简称DS)<br />Service-Oriented Component Model<br />需要对外提供的功能均定义为接口;<br />接口的实现定义以XML方式定义为Component;<br />按接口的方式访问其他Bundle的功能;<br />以XML方式定义对其他Bundle的功能的访问;<br />Component也是有生命周期的。<br />OSGi R4.0的重大改进就是这点!<br />
  24. 24. Bundle交互<br />对外提供服务示例<br />调用其他Bundle的服务示例<br />
  25. 25. Bundle交互<br />提供服务关键配置<br />provide interface,声明对外提供的接口;<br />property,可增加一些服务实现的关键词,以便匹配过滤,例如&lt;property name=“KEY” value=“DB”/&gt;<br />调用服务关键配置<br />cardinality<br />配置调用服务的数量,例如0..1、1..n、0..n;<br />policy<br />配置引用的服务变化时的策略,主要有static和dynamic这两种;<br />target<br />配置引用的服务的过滤,例如target=“(KEY=DB)”,这样即使有多个提供了接口的服务,也只会注入配置了KEY=DB的这个;<br />
  26. 26. Bundle交互<br />DS 1.1的可喜变化<br />Service-Component后指定的文件可用通配符,例如:Service-Component: OSGi-INF/*.xml<br />可以配置activate和deactivate方法,并且提供了多种方法签名的支持;<br />bind、unbind方法加了两种签名的支持;<br />void &lt;method-name&gt;(ServiceReference)<br />void &lt;method-name&gt;(&lt;parameter-type&gt;,Map)<br />增加的这个方法签名至关重要,尤其是对于按服务属性来选择服务的场景而言。<br />
  27. 27. Bundle交互<br />Component生命周期<br />如Component有对外提供服务,在没有其他Component需要此服务时,这个Component是不会被激活的,只有当有其他Component需要此服务,且当前Component所需的服务均满足条件时,才会被激活;<br />如Component没有对外提供服务,那么只要此Component所需依赖的服务均可用,则会被激活。<br />
  28. 28. Bundle交互<br />Component生命周期<br />当有Bundle启动时,会触发Declarative services的介入,以将其中的Service-Component对应的配置文件的Component载入;<br />当有Bundle通过BundleContext直接注册服务时,也将触发Declarative Services,以检查是否有Component可被激活;<br />当有Bundle STOP时,也会触发DS的介入,以将相关的OSGi Service卸载和释放,并检查相关的Component是否要被销毁;<br />如何做到引用的服务更新了,但当前Component并不会重新创建实例?<br />
  29. 29. R 4.2将会带来的变化<br />Launch Framework API<br />这个API的引入就意味着以后可以以一种统一的方式在程序中启动OSGi Framework了,示例如下:<br /> Map p=new HashMap();<br />p.put(“org.osgi.framework.storage”,System.getProperties(“user.home”)+File.separator+”osgi”);<br />FrameworkFactory factory=Class.forName(factoryClassName).newInstance();<br /> Framework framework=factory.newFramework(p);<br />framework.init();<br />BundleContext context=framework.getBundleContext();<br /> …//安装Bundles<br />framework.start();<br />framework.waitForStop();<br />
  30. 30. OSGi提供的服务<br />Http Service<br />以便支持简单的通过http访问OSGi应用;<br />但复杂的场景还是比较难支撑,这主要是由于目前还只有jetty实现的HttpService,再加上它所支持的Servlet版本太低,这也导致了目前OSGi对于Web类型的应用而言支持不足,但可喜的是RFC 66会带来很多变化;<br />Log Service<br />支持简单的日志记录,直接输出到console,不过可以结合log4j自行实现;<br />EventAdmin Service<br />基于此可实现事件通知性质的功能;<br />ConfigurationAdmin Service<br />基于此可实现配置信息的动态管理。<br />
  31. 31. OSGi对模块化、动态化的满足程度<br />模块化<br />完全满足。<br />动态化<br />能够动态的增加、删除或更新模块,并完成依赖的OSGi Service的引用迁移;<br />但要自行处理由此带来的模块中对象的状态保持和恢复的问题,因此基于OSGi了,并不就代表应用一定可动态了,要合理的基于Bundle生命周期改变和Component生命周期改变会带来的变化做相应的处理。<br />
  32. 32. 2、OSGi实现框架<br />有哪些实现框架?<br />它们是如何实现OSGi规范的?<br />它们是否遵循OSGi标准?<br />对比而言,谁更有优势?<br />
  33. 33. OSGi实现框架<br />Equinox<br />Equinox是R 4.0的RI,并且也是Eclipse的核心,可谓是久经考验,Spring-DM也是基于Equinox。<br />Felix<br />Felix作为后起之秀,表现算得上是非常突出了。<br />其他<br />Oscar、Knoperfish已是昨日黄花了;<br />
  34. 34. OSGi实现框架<br />Equinox<br />Equinox的ClassLoader结构<br />
  35. 35. OSGi实现框架<br />Equinox中的类加载顺序<br />根据启动时的bootdelegation属性判断是否需要从parent classloader中加载,具体parent classloader是哪个,则可以通过osgi.parentClassLoader属性来指定,支持的为:app(SystemClassLoader)、ext(Extension ClassLoader)和fwk(Equinox ClassLoader)三种;<br />调用Equinox的ClassLoaderDelegateHook的preFindClass来加载;<br />从Import-Package中寻找;<br />从Require-Bundle中寻找;<br />尝试从当前Bundle中加载;<br />尝试从DynamicImport-Package中加载;<br />调用Equinox的ClassLoaderDelegateHook的postFindClass来加载;<br />尝试使用Eclipse的buddy机制来加载;<br />对比规范而言,Equinox除了增加了Hook机制以及buddy机制外,完全遵守OSGi规范。<br />
  36. 36. OSGi实现框架<br />Equinox<br />Install Bundle<br />按照提供的Bundle文件加载流,并根据MANIFEST.MF的信息形成Bundle对象,并将Bundle的状态置为INSTALLED;<br />对外广播Bundle INSTALLED事件。<br />
  37. 37. OSGi实现框架<br />Equinox<br />Resolve Bundle<br />如bundle为singleton,则首先检查singletons bundle是否已存在,如存在则resolve失败;<br />对所依赖的package进行寻找、检查和绑定;<br />寻找require-bundle、import-package匹配的bundle;<br />检查这些bundle之间是否有冲突,尽可能的选择没有冲突的bundle;<br />绑定通过检查的bundle,以便在加载类时可直接去这些bundle中寻找。<br />将Bundle状态设置为RESOLVED。<br />
  38. 38. OSGi实现框架<br />Equinox<br />Start Bundle<br />检查状态是否为RESOLVED,如未resolve则先进行resolve动作,resolve失败则直接抛出异常,成功则继续下面步骤;<br />调用MANIFEST.MF中配置的bundle-activator对应的类的start方法。<br />将Bundle状态置为ACTIVE。<br />
  39. 39. OSGi实现框架<br />Equinox<br />Stop Bundle<br />注销发布的OSGi服务以及释放对其他OSGi服务的引用;<br />调用MANIFEST.MF中配置的bundle-activator的类的stop方法;<br />将Bundle状态置为RESOLVED。<br />
  40. 40. OSGi实现框架<br />Equinox<br />Uninstall Bundle<br />如Bundle为Active,先停止Bundle;<br />检查是否有其他Bundle依赖了当前Bundle的package,如有则先不关闭此bundle的classloader,如没有则关闭;<br />将Bundle状态置为UNINSTALLED。<br />
  41. 41. OSGi实现框架<br />Equinox<br />Update Bundle<br />如状态为ACTIVE,先停止;<br />创建新的Bundle对象,如有Bundle依赖老版本的Bundle,则暂时将老版本的Bundle放入removalPendings中,如没有,则清除老版本Bundle的所有信息;<br />恢复新版本的Bundle到更新前的状态。<br />
  42. 42. OSGi实现框架<br />Refresh<br />找到所有removalPendings中的bundle,unresolve这些bundle,并重新resolve依赖了这些bundle的bundle;<br />恢复重新resolve了的bundle的状态。<br />
  43. 43. OSGi实现框架<br />Equinox<br />DS在这些过程中的处理<br />Start Bundle时<br />扫描MANIFEST.MF中对应的Service-Component指定的文件,加载这些文件;<br />判断其中指定的Component是否符合激活条件,如符合,则激活并调用activate方法,对于提供了OSGi Service的Component,则注册此OSGi Service;<br />Stop Bundle时<br />不做任何动作;<br />有服务注册时<br />寻找当前的Component是否有可激活的,如有则进行激活;<br />寻找当前已激活的Component中是否有需要此OSGi Service的,如有则调用其bind-method进行注入;<br />有服务注销时<br />对于依赖了此OSGi Service的component,调用其unbind-method;<br />检查是否有Component因此不到激活条件的,则尝试调用Component的deactivate方法并销毁Component的实例。<br />
  44. 44. OSGi实现框架<br />Felix<br />Felix的ClassLoader结构<br />
  45. 45. OSGi实现框架<br />Felix中的类加载顺序<br />判断是否为bootdelegation中配置的package,如交由Felix ClassLoader进行加载;<br />尝试从Import-Package中加载,如在则交由相应的Bundle ClassLoader去加载,即使加载不到也继续下面的步骤;<br />尝试从当前Bundle的Classpath中加载;<br />尝试从DynamicImport-Package中加载;<br />从上面步骤来看,Felix在Import-Package时这步上未遵循OSGi规范,这有些时候可能会造成一些问题。<br />
  46. 46. OSGi实现框架<br />Felix<br />Install Bundle<br />解析Bundle的MANIFEST.MF文件,读取OSGi标准中定义的头信息;<br />检查Bundle的唯一性,如不唯一则抛出异常;<br />将Bundle状态置为INSTALLED。<br />
  47. 47. OSGi实现框架<br />Felix<br />Resolve Bundle<br />寻找需要依赖的Package或Bundle,并将其中未resolve的Bundle进行resolve,如resolve失败,则将其从潜在的Bundle列表中删除,这步完全遵循OSGi规范;<br />检查是否有符合条件的Bundle,如没有,则抛出异常,有则继续;<br />检查这些符合条件的潜在的Bundle,如多个同名称的单态Bundle、版本冲突等问题,如这些问题均不存在,则继续下面的步骤;<br />完成绑定。<br />
  48. 48. OSGi实现框架<br />Felix<br />Start Bundle<br />检查Bundle状态,如未resolve则先resolve;<br />执行MANIFEST.MF中对应的Bundle-Activator配置的类的start方法,如未配置则跳过此步;<br />将Bundle状态设置为ACTIVE;<br />
  49. 49. OSGi实现框架<br />Felix<br />Stop Bundle<br />执行MANIFEST.MF中对应的Bundle-Activator配置的类的stop方法,如未配置则跳过此步;<br />注销Bundle对外发布的Service;<br />释放Bundle引用的Service;<br />
  50. 50. OSGi实现框架<br />Felix<br />Uninstall Bundle<br />检查状态,如为ACTIVE,则先停止;<br />如有其他Bundle引用了当前Bundle的package,则将当前Bundle的RemovalPending设置为true;<br />将Bundle状态设置为UNINSTALLED;<br />如未被其他Bundle使用,则对当前Bundle执行refresh动作;<br />
  51. 51. OSGi实现框架<br />Felix<br />Update Bundle<br />停止当前的Bundle;<br />重新读取并解析Bundle流,将Bundle状态置为INSTALLED;<br />恢复Bundle到更新前的状态。<br />
  52. 52. OSGi实现框架<br />Felix<br />Refresh<br />在指定Bundle的情况下,递归找到依赖当前Bundle提供的package的Bundle,作为此次refresh动作需要操作的Bundles;在未指定Bundle的情况下,则将已卸载的且RemovalPending为true的Bundles,以及还未resolve的Bundle作为此次需要操作的Bundles;<br />refresh负责将需要uninstall的Bundle对外export的package彻底关闭,并对需要依赖这些package的bundle执行STOP动作;<br />对于不需要Uninstall但在refresh动作范畴的bundles恢复为之前的状态。<br />
  53. 53. OSGi实现框架<br />Felix<br />DS在这些过程中的处理<br />和Equinox基本一致;<br />但值得注意的是Felix DS 1.0.8对于policy=dynamic、cardinality=“0..1” | “0..n”这类依赖服务变更时的处理有个bug,会造成在依赖的服务更新后出现需要此服务的Component拿不到服务引用的现象。<br />
  54. 54. OSGi实现框架对比<br />
  55. 55. 3、扩展Equinox<br />如何在外部程序中启动Equinox?<br />是否可以对Equinox进行扩展?<br />如可以扩展,应如何做?<br />
  56. 56. 扩展Equinox<br />在外部程序中启动Equinox<br />示例<br /> // 配置Equinox的启动<br />FrameworkProperties.setProperty(&quot;osgi.noShutdown&quot;, &quot;true&quot;);<br />FrameworkProperties.setProperty(&quot;eclipse.ignoreApp&quot;, &quot;true&quot;);<br />FrameworkProperties.setProperty(&quot;osgi.bundles.defaultStartLevel&quot;, &quot;4&quot;);<br />FrameworkProperties.setProperty(&quot;osgi.bundles&quot;, &quot;// 指定需要装载的Bundle的路径&quot;);<br /> // 指定需要加载的bundles所在的目录<br />FrameworkProperties.setProperty(&quot;osgi.syspath&quot;, &quot;// 例如plugins&quot;);<br />EclipseStarter.run(new String[]{&quot;-configuration&quot;,&quot;configuration&quot;,&quot;-console&quot;}, null);<br /> // 通过EclipeStarter获取到BundleContext<br /> context=EclipseStarter.getSystemBundleContext();<br />到了R 4.2后就可以遵循标准的API来启动了<br />
  57. 57. 扩展Equinox<br />Equinox中可用的扩展<br />ClassLoadingHook<br />ClassLoaderDelegateHook<br />ClassLoadingStatsHook<br />AdaptorHook<br />借助这些扩展可以更好的控制Equinox。<br />
  58. 58. 扩展Equinox<br />ClassLoadingHook<br />可用于拦截Bundle ClassLoader的创建、类的处理、Classpath的处理等;<br /><ul><li>ClassLoaderDelegateHook
  59. 59. 可用于在某个阶段干预类的加载,例如在类从Import-Package中扫描之前或在DynamicImport-Package扫描之后。</li></li></ul><li>扩展Equinox<br /><ul><li>ClassLoadingStatsHook
  60. 60. 可用于拦截类从Bundle-Classpath中加载的动作,包括加载之前以及加载之后。</li></ul>AdaptorHook<br />可用于拦截BaseAdaptor的创建过程,例如在初始化时、framework启动时、停止时。<br />
  61. 61. 扩展Equinox<br />注册Hook类的方法<br />属性中指定<br />在启动时指定osgi.hook.configurators,但要注意的是要加上目前Equinox所需的hooks配置,格式为:<br />hook.configurators=hook类名,hook类名<br />此文件需要放在Equinox框架的classpath下;<br />配置文件中指定<br />增加一个hookconfigurators.properties,其中的格式为:<br />hook.configurators=hook类名,hook类名<br />
  62. 62. Equinox扩展的启示<br />框架级的软件都应提供良好的扩展支持,方式可以为:<br />Filter<br />可通过扩展OSGiService模型来实现;<br />适合组装为一连串的处理来完成一个功能。<br />Interceptor<br />可通过扩展OSGi Service模型来实现;<br />适合方法执行前后的扩展处理;<br />Hook<br />直接基于OSGi Service模型即可实现;<br />适用于方法执行过程中的扩展处理;<br />
  63. 63. 4、Equinox高级实战<br />将上节的东西应用到实战中!<br />如何控制Equinox的ClassLoader?<br />如何将非DS的应用迁移为DS方式?<br />如何应对采用OSGi后一些常见的错误?<br />
  64. 64. Equinox高级实战<br />控制Equinox的ClassLoader<br />基于ClassLoaderDelegateHook实现<br />实现ClassLoaderDelegateHook以及HookConfigurator接口;<br />可自行控制是在Import-Package寻找前进行类或资源加载的处理还是在之后;<br />增加hook.configurators文件或修改启动属性:osgi.hook.configurators。<br />实际的一个场景<br />有些Bundle类需要加载外部容器中的类,就可以用这种方法。<br />
  65. 65. Equinox高级实战<br />将非DS的应用迁移为DS方式<br />迁移的方法<br />将之前直接类的调用方式改为基于接口的方式,这也将对动态化的实现更为有利;<br />将接口放入一个独立的Bundle中,也是为了动态化;<br />将注册服务的代码去掉,改为通过编写xml文件来注册服务;<br />将调用服务时依赖BundleContext获取的方式去掉,改为set注入的方式,并通过unset来感知服务的注销;<br />编写XML文件来定义需要调用的OSGi Service;<br />最后就是在运行的Bundle中增加DS实现的Bundle。<br />
  66. 66. Equinox高级实战<br />将非DS的应用迁移为DS方式<br />示例<br />迁移好处<br />解放之前对于BundleContext.registerService等这些难用的用法;<br />避免需要自己基于ServiceTracker或ServiceListener来实现服务状态的感知。<br />
  67. 67. Equinox高级实战<br />将非DS的应用迁移为DS方式<br />DS的四种经典用法<br />set注入单个依赖的服务;<br />&lt;reference name=… interface=… bind=… unbind=… policy=…/&gt;<br />set注入单个指定标识的依赖的服务;<br />&lt;reference name=… interface=… bind=… unbind=… policy=… target=“(key=DB)”/&gt;<br />set注入多个依赖的服务,在调用时进行全调用,类似filter chain或hook;<br />&lt;reference name=… interface=… bind=… unbind=… policy=… cardinality=“0..n”/&gt;<br />set注入多个依赖的服务,调用时根据某标识来调用其中的一个服务,实现类似的Factory机制;<br />&lt;reference name=… interface=… bind=… unbind=… policy=… cardinality=“0..n”/&gt;<br />set方法签名则改为void &lt;method-name&gt;(interface,Map) (必须是DS 1.1+)<br />从上面四种用法来看,DS甚至强于了现在所有的IoC容器。<br />
  68. 68. Equinox高级实战<br />经常会碰到的一些问题<br />ClassNotFoundException<br />几乎是所有使用OSGi的人都会经常碰到的问题;<br />解决的方法是掌握Bundle Class的加载方式;<br />ClassCastException<br />几乎是所有使用OSGi的人都会经常碰到的问题;<br />解决的方法是掌握ClassLoader的基本原理以及Bundle Class的加载方式;<br />OSGi Component没启动<br />这是比较麻烦的问题;<br />解决的方法首先是掌握OSGi Component的激活条件;<br />然后是通过OSGi Console,查看log,或仔细检查Component .xml的配置;<br />
  69. 69. 5、分布式OSGi<br />有哪些实现框架?<br />它们是如何实现的?<br />对比而言,谁更有优势?<br />
  70. 70. 分布式OSGi<br />你所期望的?<br />我所期望的<br />透明的将OSGi服务发布为可远程调用的服务;<br />透明的调用远程的OSGi服务;<br />OSGi服务的动态化感知不是必须的<br />由于这受限于网络等各种因素,而且如果服务有多级调用的话就会出现类似的雪崩效应;<br />
  71. 71. 分布式OSGi<br />Java远程通信<br />(TCP/IP、UDP/IP、多播)+NIO/BIO<br />Java远程RPC<br />RMI:基于代理、反射机制<br />Webservice:基于http RPC机制<br />
  72. 72. 分布式OSGi<br />分布式OSGi<br />R-OSGi<br />老牌,有一定的优势,但用户群不多;<br />CXF DOSGi<br />作为将来的R 4.2的RFC119的实现,值得期待!<br />
  73. 73. 分布式OSGi<br />R-OSGi<br />能达到的效果<br />透明的将OSGi Service对外发布;<br />只需要在注册OSGi Service时加上properties.put(RemoteOSGiService.R_OSGi_REGISTRATION, Boolean.TRUE);<br />属性<br />透明的调用远程的OSGi Service;<br />只需获取RemoteOSGiService,然后就可以调用远程的OSGi Service;<br />由于调用时基于的是TCP/IP,例如其提供了基于mina的调用,因此性能还是不错的;<br />可基于jSLP实现Service Discovery,从而更加简单的找到需要调用的远程OSGi Service。<br />
  74. 74. 分布式OSGi<br />R-OSGi<br />实现机制<br />监听了服务注册事件,当有服务注册时,检查其注册的属性,如属性中有RemoteOSGiService.R_OSGi_REGISTRATION,并且值为true,那么则做一个服务接口名与此服务的映射,并将此映射作为tcp/ip某端口的处理器集合。<br />对于客户端,当通过RemoteOSGiService拿到引用时,为一个服务端调用的代理,当调用此引用的方法时,即代理访问到远端服务器,过程即为一个类似的自定义的java远程RPC。<br />
  75. 75. 分布式OSGi<br />CXF DOSGi<br />能达到的效果<br />透明的将OSGi Service对外发布;<br />只需在注册服务时增加如下属性即可:<br />props.put(&quot;osgi.remote.interfaces&quot;, &quot;*&quot;);<br />props.put(&quot;osgi.remote.configuration.type&quot;, &quot;pojo&quot;);<br />props.put(&quot;osgi.remote.configuration.pojo.address&quot;, WebService URL);<br />透明的调用远程OSGi Service<br />增加一个remote-services.xml,按照格式描述所需调用的远程OSGi Service;<br />调用时直接以接口的方式调用远程OSGi Service即可,完全透明;<br />从这点对比而言,CXF DOSGi要强于R-OSGi,毕竟R-OSGi的完全透明还是需要做点包装的。<br />
  76. 76. 分布式OSGi<br />CXF DOSGi<br />实现机制<br />监听服务注册事件,当注册时有相应的属性时,则将其发布为Webservice;<br />对于客户端,则通过扫描相应的service-description的描述来生成一个调用远程Webservice的代理,并将此代理注册为相应的OSGi Service。<br />
  77. 77. 分布式OSGi<br />个人的经验<br />分布式OSGi的实现多数和OSGi并没有多大的关系,其核心原理均为实现一个透明的远程RPC;<br />如需关注性能、稳定性来说完全可以自行实现;<br />所需的知识为代理、反射、网络通信以及服务发现;<br />
  78. 78. END!<br />
  1. A particular slide catching your eye?

    Clipping is a handy way to collect important slides you want to go back to later.

×