`

Java模块化编程--OSGI之三个概念层

    博客分类:
  • OSGI
阅读更多

前言

 

在最近做的一个项目中,需要实现对jar包的热更新,最初的实现方式是使用自定义的ClassLoader。但这种自定义ClassLoader的方式只能实现首次jar包的热加载(即在程序启动后,引入新的jar包到jvm),如果要更新这个jar包版本却没有办法。

 

具体为啥没有办法实现对jar包的热更新呢,假设现在jar1.0中对应的class文件使用自定义的ClassLoader已经加载到JVM内存,生成了对应版本的Class对象,这些对象都会被缓存起来(放到方法区中)。此时如果更新jar2.0,由于缓存中已经存在(方法区)老版本的Class对象,新的class文件是无法加载到JVM中的。由于jvm中没有提供classclassloader的卸载方法,要自己去实现是个复杂的过程。

 

这其实就涉及到java的模块化编程,OSGI刚好就是现在比较成熟的技术解决方案,而且大名鼎鼎的Eclipse就是基于OSGI实现了对插件的热插拔(Eclipse 3.0以后)。引入这项技术后很好的解决了我们面临的问题。另外jdk1.9也推出了自己的模块化编程解决方案Jigsaw,但目前jdk1.9还没有大范围商用,在技术选型时被排除。

 

在现有项目中使用OSGI还是有一定的学习成本,准备对OSGI的引入过程做一些总结。首先从一些理论基础开始。

 

OSGI的三个概念层

 

OSGI规范和OSGi框架:OSGI规范是由OSGI联盟制定的一套技术规范,本质就是一系列的接口;OSGI框架 简单的理解就是各个软件厂商对OSGI规范中定义的接口的实现,比较有名的三个OSGI框架:Apache FelixEclipse EquinoxKnopflerfishOSGI规范和OSGi框架的关系有点类似于jvm规范和Hotspot虚拟机。

 

OSGI的三个概念层,确切的说应该是OSGI规范定义的三个概念层:模块层、生命周期层、服务层。

 

模块层:OSGI的每个模块都称之为bundle,它是一个包含元数据的jar文件。与普通jar的区别是每个bundle对应的jar包中有一个META-INF目录,里面有一个MANIFEST.MF文件(现在大部分通过Maven引入的jar包中都有这个文件),该文件就是“元数据”。可以简单的理解bundle=普通jar+MANIFEST.MF(元数据描述文件),所以MANIFEST.MF文件就是boundle的核心。

 

MANIFEST.MF文件可以定义哪些包(package)对外可见(export导出),这个bundleOSGI容器中被加载后,其它bundle通过import导入需要的包(package),使用这些包中的类。

 

这里有一个exportimport的概念,bundle之间的API相互依赖都可以通过exportimport相关的包(package)来完成。在一个bundle中只有export导出的api才能被其他bundle使用,即使是定义为publicapi如果没有被export导出,对于其它bundle来说是不可见的。这这个层面上讲,bundle扩展了java的访问修饰符:public、默认、privateprotected

 

简单的理解模块层,就是在jar包的基础上加元数据,也就是配置MANIFEST.MF文件,一个简单的MANIFEST.MF配置文件如下:

Manifest-Version: 1.0
Archiver-Version: Plexus Archiver
Created-By: Apache Maven
Built-By: gantianxing
Build-Jdk: 1.8.0_65
Bundle-Activator: com.sky.osgi.MtActivator
Bundle-ManifestVersion: 2
Bundle-SymbolicName: osgibundle222
Import-Package: com.sky.osgi.server

 

 

后面再抽时间单独对MANIFEST.MF文件的配置方法单独进行总结。

 

生命周期层:顾名思义,其主要作用是控制如何管理bundle的生命周期,比如bundle的在容器里的安装、更新、启动、停止、卸载,以及如何管理应用程序。这些API都是在生命周期层定义。在这一层,OSGI规范中定义了很多接口来实现对bundle的管理,后面再抽时间进行总结。

 

服务层:这层的概念有点类似SOA服务治理,与SOA服务治理一样 OSGI的服务层包含:服务注册中心、服务提供方、服务使用方(客户端)。与SOA服务不同的是,OSGI的服务层的注册中心、服务提供方、服务使用方都在一个jvm实例内部,而SOA的服务是分布式的。这也就是所谓的:OSGIJVM内部的SOA服务治理框架。

 



 

                    摘自《OSGI实战》

 

OSGI的工作流程如上图,可见其工作方式与普通RPC框架是类似的(比如Dubbo),这里只是在一个jvm实例中完成:首先服务提供者向注册中心发布服务,客户端要使用某个服务时首先到注册中心查找,如果找到对应的服务,就直接调用该服务(有点类似服务直连)。

 

另外OSGI服务的开发模式也跟普通的RPC服务类似,是一种基于接口的开发模式,实现与接口分离。在发布服务时,只需把接口类暴露出去(export),服务使用方导入这些接口类再通过注册中心查找即可。

 

注意这里使用服务与普通export的区别,使用服务:服务提供方只是往外暴露(export)了接口类,具体的实现类对客户端(另一个bundle)来说是不可见的;普通的export是导出整个具体的实现类,客户端导入后可以直接使用。简单理解就是,前者只是export接口隐藏实现,后者是直接export实现。

 

相对于直接export实现类来说,使用服务发布的方式有很多好处:服务端是一个bundle 具体的实现被封装到这个bundle中,客户端是其它bundle,当服务端有内容需要更新时,客户端是无感知的。就类似于普通的RPC框架里,服务提供方法有代码更新需要重新上线,而对服务使用方(客户端)来说是不需要同步上线的。这应该就是OSGI能实现热更新的根本原因:



 

如果上图bundle1-3是服务使用方,bundle4-6是服务提供方(当然也可以即使服务提供方,也是其它服务的使用方,最终可能是一个网状结构),比如:当服务提供方bundle4需要更新重新加载时,此时这个服务只是短时间不可用,其它bundle可以正常工作,只是bundle1在调用bundle4的服务时,发现服务不可用,这时可以进行异常处理或者进行轮询等待即可。

 

 

关于OSGI的三个概念层,本次总结只是简单的从理论概念上进行了描述,具体模块层元数据怎么配置?生命周期层如果管理?服务层如何注册和发现服务?对于这三个问题,后面再单独抽时间总结下。

  • 大小: 48.5 KB
  • 大小: 12.5 KB
0
0
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics