从写单个类的打印Hello World小程序到OSGi模块化开发,确实存在较大的难度,本文将从模块化、OSGI模型以及OSGI在OpenDaylight中的应用等方面进行介绍。
一、模块化
我们学习Java语言时,最初写的程序便是在控制台打印Hello World,此时,我们写的代码放在一个类中;慢慢地,我们编写的代码需要放在几个的类时,我们就要考虑如何设计类与类之间的关系,你需要面向对象的设计原则和模式;工作中我们要做一个小项目,就可能涉及到数百个类了,我们会根据不同的业务职责将这些类进行逻辑上的划分,分隔不同的小模块,每个小模块赋予相应的职责,也就是将一个系统分解为多个较小的互相协作的单元,并设定单元之间的边界来改善系统的维护性和封装性。大致过程如下图①②③所示:
至目前为止,我们所做的事情是对类进行了逻辑的包装,而实质上并没有对类进行物理隔离。通常情况下,软件在初始构建时,并不是很复杂,但随着时间的推移、业务特性的增加、不规范的代码调用以及为赶进度而忽略架构的设计,就使得软件变得复杂起来,甚至极难维护。如同双11爆仓时凌乱不勘的场景:
图片来自互联网
那么如何降低软件的复杂性呢?生活中的货物运输或许是一个很好的借鉴例子,我们将零散的货物打包在一起,形成封闭的空间;然后,通过标准的接口装载到集装箱运输船。
事实上,早在1972年国际软件工程大师David Parnas在《On the Criteria To Be Used in Decomposing Systems into Modules》一文中就提出了模块化编程的思想:“每项任务构成一个独立的、特有的程序模块。实现时,每个模块及其输入/输出都有确定含义的......系统以模块化的方式进行维护”,其实质就是软件模块划分应该以基于信息隐藏为目的,以职责划分为手段,从而封装变化。联想到集装箱的例子,软件的模块可以类比为集装箱,如下图所示:
我们现在正式介绍软件模块,在《Java应用架构设计 模式与OSGI》一书中进行了描述:软件模块是可部署的、可管理的、原生可重用的、可组合的、无状态的软件单元,它为用户提供了简洁的接口。
① 可部署:模块是一个独立的部署单元,它能够与其他软件模块共处。EAR、WAR以及JAR文件。
② 可管理:在运行时,模块可以进行安装、卸载以及更新。实体样例:EAR、WAR以及JAR文件。
③ 原生可调用:模块总是原生可调用的。也就是说,模块暴露的操作是通过直接调用方法触发的。
④ 可组合:一般指的是粗粒度的模块是由细粒度的模块组成的。
⑤ 无状态:特定版本的模块只会存在一个实例。
由前面的分析可知,Java模块化支持局限于细粒度的面向对象支持,需要有更高抽象粒度的模块。OSGi便是Java模块化需求其中一个解决方案。
一、OSGi
OSGi(Open Services Gateway initiative,开放服务网关协议)是由 1999 年成立的 OSGi 联盟提出的一个开放的服务规范,最早用于嵌入式设备。在2004年,Eclipse发布于基于OSGi的运行时模型,把 Equinox 作为底层运行平台。借助于Eclipse,OSGi在商业化软件企业中得到广泛的关注。现已广泛应用于移动设备、桌面应用以及企业应用服务器。
OSGi框架是应用的执行环境。OSGi框架规范定义了OSGi的行为,现已有Apache Felix、Eclipse Equinox以及Knopflerfish等多个开源实现。OSGi的分层架构如下:
模块层定义了模块,称为Bundle,体现为一个JAR文件,由类文件、资源文件和MANIFEST.MF组成。和普通的jar文件唯一不同的就是MANIFEST.MF文件的内容,基本上都是标识Bundle的属性,Import-Package声明了请求JAR文件中的代码所需要的外部包。其文件样例为:
生命周期层定义了动态安装和管理Bundle,即可以在框架中安装和卸载bundle,而不需要重启应用进程。
服务层定义了面向服务的应用编程模型,涉及面向服务的发布、查找和绑定交互模式:服务提供者将服务发布到服务注册中心,然后服务请求者通过搜索服务注册中心,查找可供使用的服务。这种机制称为VM中的SOA。事实上,服务就是Java接口。
3.OSGi生态
4.Bundle交互
了解了OSGi基础知识后,我们来看下Bundle交互的实现方式:
(1) Export和Import:即通过Package的Export和Import来进行。服务提供者Bundle对外Export自己的package,而服务请求者则根据业务需要Import外部的Package;
(2) service:服务提供者Bundle对外提供Service,而服务请求者查找Service。而提供Service的方式又有:
① 通过BundleContext(Bundle上下文)来提供和获取;
② 通过Declarative Service来实现;
③ 通过Blueprint来实现;
在这里,我们重点介绍第3种方式--Blueprint。Blueprint提供一个依赖注入框架来实现OSGI,并在OSGI Compendium R4.2里被OSGI组织标准化。Blueprint的强大之处在于即具有Spring强大且非侵入性的企业级编程模型又具有OSGi的动态性、模块化的特性。
Bundle间的交互使用类似Spring Bean的方式配置定义,Blueprint的XML文件定义和描述不同Bundle的组装。一个简单的Blueprint示例如下:
XML文件的命名空间标识blueprint 1.0.0版本。顶级的blueprint元素标识XML文件作为一个blueprint模块来定义;reference元素标识从OSGi服务注册中心为组件获得一个服务;bean元素标识与Spring Bean相同的含义。
一、OSGi在OpenDaylight中的应用
Java模块化的局限和OSGi框架的模块化标签,使得Java和OSGi走在了一起,进而增加了Java模块化开发的能力。
作为SDN控制器,OpenDaylight使用了Java语言编写,SDN控制器本身的功能与协议繁多导致了其子项目众多,如何更好地按需动态加载所需的项目成为技术选型的一个重要因素。而OSGi的如下特性也使得其在OpenDaylight中发挥很大的作用:
① 将一个程序打包成逻辑上独立的JAR文件,并且只部署那些某个安装所需要的部分。
② 将一个程序打包成逻辑中独立的JAR文件,声明哪些代码可以被其他JAR文件访问,并且强调可见性。
③ 为程序提供一个插件式的扩展机制。OSGi模块化特别适合提供强大的扩展机制,包括支持执行时的动态性。
OpenDaylight采用了OSGi框架之后,那开发一个应用程序的流程又是怎样的呢?下面给出一般方法:
① 根据应用的业务场景设计Bundle,并设计Bundle的服务;
② 使用IDE实现Bundle,配置Blueprint容器XML文件;
③ 打包和部署Bundle的JAR文件;
④ 启动类似Karaf之类的部署环境,并根据业务需要安装Bundle。
事实上,OpenDaylight不仅采用了OSGi框架,而且还使用了Apache Karaf这个企业级容器,下篇文章我们将探讨Apache Karaf的基础知识。
全部0条评论
快来发表一下你的评论吧 !