OSGi理论和实战目标学习OSGi规范R4.1,掌握OSGi核心概念;学习OSGiR4实现框架的实现机制,以更好的使用这些框架;学习基于Equinox开发OSGiBased的应用;扩展Equinox,更好的基于Equinox来开发各类应用;学习分布式OSGi;大纲OSGi介绍OSGi实现框架扩展EquinoxEquinox高级实战分布式OSGi1、OSGi介绍在OSGi中,模块是什么?模块之间的类是如何做到隔离的?怎么访问其他模块中的类?模块的生命周期是怎么样的?模块之间怎么交互?OSGi提供了哪些常用的Service?我期望的模块化、动态化模块化(Java7中最重要的Feature)独立,不受其他模块的影响;其他模块只能访问该模块对外提供的功能;模块具备独立的生命周期,例如启动、停止、更新等。动态化能动态的增加、更新或删除模块,而对于模块来说不需要做额外的处理;你期望中的?OSGi是什么一个标准,基于此标准实现的框架可轻松的构建模块化、动态化的系统;DynamicModuleSystemForJava;JSR232、JSR291;众多JavaApplicationServer(Weblogic、Glassfish等)所选择的底层框架;BundleBundle是OSGi中部署的最小单位,因此可以认为Bundle就是模块;Bundle就是一个普通的jar包,只是其在MANIFEST.MF中加入了一些特殊的头信息,例如Bundle-Name;Bundle类隔离机制JavaClassLoader机制类由ClassLoader来实现加载,Java动态化实现的基础;默认情况下有BootStrapClassLoader(jre/lib、jre/classes)、ExtensionClassLoader(jre/lib/ext)以及SystemClassLoader(-classpath指定)三个级别的ClassLoader;应用可自行实现ClassLoader以动态的加载类,或加载相应目录下的类;Bundle类隔离机制每个Bundle均为独立的ClassLoader,典型的Bundle的ClassLoader结构如下所示:SystemClassLoaderFrameworkClassLoaderBundleClassLoaderBundle-Classpath中指定的jar或路径BundleClassLoaderBundle-Classpath中指定的jar或路径BundleClassLoaderBundle-Classpath中指定的jar或路径Bundle类共享机制Java经典的Delegation模型在寻找类时首先从parentclassloader中寻找,如找不到才在当前classloader中寻找;Bundle类共享机制Bundle类加载过程java.*委派给parentclassloader加载;bootdelegation参数中配置的也委派给parentclassloader加载,在parentclassloader中未找到也继续下面的步骤;是否在Import-Package中,在则委派给Export-Package的bundle的classloader;是否在Require-Bundle中,在则委派给相应的BundleClassLoader,未找到则继续下面步骤;在Bundle-Classpath中寻找,未找到则继续下面的步骤;在fragmentsbundle的classpath中寻找,未找到则继续下面的步骤;是否在Export-Package中,未找到则继续下面的步骤;是否在DynamicImport-Package中,在则委派给相应的BundleClassLoader寻找,不在则抛出ClassNotFound异常。Bundle类共享机制因此可以通过在MANIFEST.MF中定义Require-Bundle、Import-Package、Export-Package以及DynamicImport-Package来实现类共享;Import-Package:org.osgiusers.china.demoExport-Package:org.osgiusers.china.demoDynamicImport-Package:org.osgiusers.*注意:OSGi支持包的版本的定义!Import-Package:org.osgiusers.china.demo;version=“[1.0,2.0)”Bundle类共享机制Import-Package寻找机制比较提供了相应package的Bundle的状态,resolved优先于未resolved的;如均为resolved的bundle,则比较package的版本,默认package版本为0.0.0,版本高的优先于版本低的;如版本也一样,则比较bundleid,bundleid小的优先于大的,也就是先安装的bundle优先。Bundle生命周期OSGi按照下面的状态转换方式来管理Bundle的生命周期;可通过OSGi提供的API来主动改变Bundle的生命周期。BundleContext.installBundleBundle.startBundle.updateBundle.stopBundle.uninstallBundle生命周期改变时所做的动作将直接影响动态化。INSTALLEDRESOLVEDUNINSTALLEDACTIVESTOPPINGSTARTINGstartstopBundle生命周期InstallBundle时要做的事情解析Bundle的MANIFEST.MF信息,判断格式是否符合标准以及是否存在相同的Bundle;分配新的BundleID后;生成Bundle对象,并放入已安装的Bundles集合中,状态置为INSTALLED。Bundle生命周期ResolveBundle时要做的事情寻找Bundle中所需依赖的包或Bundle是否存在以及被resolve,包括寻找匹配的import-package、require-bundle等,如寻找到则进入检查,检查完冲突后形成绑定关系,以便加载类时能直接加载;冲突示例ABundle依赖org.osgiusers.china.demo;version=1.0.0,org.osgiusers.china.user;version=2.0.0;BBundle提供了org.osgiusers.china.demo;version=1.0.0,但同时import了org.osgiusers.china.user;version=1.1.0如成功,则将Bundle状态置为RESOLVED。Bundle生命周期StartBundle时要做的事情检查Bundle的状态,如未Resolve,则先Resolve;寻找MANIFEST.MF中配置的Bundle-Activator,如寻找到,则调用其start方法;将Bundle状态标识为ACTIVE。Bundle生命周期StopBundle时要做的事情卸载当前Bundle对外提供的所有OSGiService,并释放当前Bundle引用的所有OSGiService;调用MANIFEST.MF中对应的Bundle-Activator的类的stop方法;将Bundle状态置为RESOLVED。Bundle生命周期UninstallBundle时要做的事情检查Bundle状态,如状态为ACTIVE,则先STOP;释放Bundle对其他Bundle的类依赖;如当前Bundle中有其他Bundle的类依赖,则进行记录,如没有则释放该Bundle的ClassLoader;将当前Bundle的状态置为UNINSTALLED。Bundle生命周期UpdateBundle时要做的事情首先停止当前Bundle;重新安装并RESOLVEBundle;恢复到Bundle更新之前的状态。Bundle生命周期总结除了DynamicImport-Package外,其他的Package引用哪个Bundle在Resolve时就已经决定了;如希望更新Bundle所引用到的类,则必须进行refresh动作;但refresh动作也只对目前处于unresolve状态的以及之前uninstall时还有其他bundle类依赖的Bundle进行unresolve动作,并重新resolve对他们有依赖的bundle。从上可见,当Bundle有Start动作时,有可能会造成有Bundle的ClassLoader建立成功,当发生Refresh动作时,有可能会造成某些BundleResolve失败,也有可能造成某些Bundle重建ClassLoader。Bundle交互直接类访问的方式(不推荐),结合上面之前的Bundle生命周期的介绍,为什么?;Service交互方式直接通过BundleContext.getServiceReference以及BundleContext.registerService这样的方式(使用不方便,不推荐);DeclarativeServices方式,类似IoCtype2;BundleBundleJAVAOperatingSystemHardwareOSGiFrameworkServiceregistrypackagespackagesBundle交互DeclarativeServices(简称DS)Service-OrientedComponentModel需要对外提供的功能均定义为接口;接口的实现定义以XML方式定义为Component;按接口的方式访问其他Bundle的功能;以XML方式定义对其他Bundle的功能的访问;Component也是有生命周期的。OSGiR4.0的重大改进就是这点!Bundle交互对外提供服务示例调用其他Bundle的服务示例Bundle交互提供服务关键配置provideinterface,声明对外提供的接口;property,可增加一些服务实现的关键词,以便匹配过滤,例如propertyname=“KEY”value=“DB”/调用服务关键配置cardinality配置调用服务的数量,例如0..1、1..n、0..n;policy配置引用的服务变化时的策略,主要有static和dynamic这两种;target配置引用的服务的过滤,例如target=“(KEY=DB)”,这样即使有多个提供了接口的服务,也只会注入配置了KEY=DB的这个;Bundle交互DS1.1的可喜变化Service-Component后指定的文件可用通配符,例如:Service-Component:OSGi-INF/*.xml可以配置activate和deactivate方法,并且提供了多种方法签名的支持;bind、unbind方法加了两种签名的支持;voidmethod-name(ServiceReference)voidmethod-name(parameter-type,Map)增加的这个方法签名至关重要,尤其是对于按服务属性来选择服务的场景而言。Bundle交互Component生命周期如Component有对外提供服务,在没有其他Component需要此服务时,这个Component是不会被激活的,只有当有其他Component需要此服务,且当前Component所需的服务均满足条件时,才会被激活;如Component没有对外提供服务,那么只要此Component所需依赖的服务均可用,则会被激活。Bundle交互Component生命周期当有Bundle启动时,会触发Declarativeservices