微内核架构也被称为插件化架构,它是一种面向功能进行拆分的可扩展性架构,通常用于实现基于产品的应用(product-based与web-based相对),微内核架构包含两类组建:核心系统和插件模块,核心系统负责和具体业务无关的通用功能,例如模块加载,模块间通信等;插件模块负责实现具体的业务逻辑

架构师修炼系列【微内核架构】_架构师养成记


核心系统功能比较稳定,不会因为业务功能扩展而不断修改,插件模块可以根据业务功能的需要不断地扩展。微内核架构通过隔离变化到插件的方式提供了灵活性、可扩展性

设计关键

微内核的核心系统设计的关键技术有几部分 : 插件管理、插件连接和插件通信

  • 插件管理
    核心系统需要知道当前有哪些插件可用,如何加载这些插件,什么时候加载插件。常见 的实现方法是插件注册表机制,核心系统提供插件注册表(可以是配置文件,也可以是代码,还可以是数据库),插件 注册表含有每个插件模块的信息,包括它的名字、位置、加载时机(启动就加载,还是 按需加载)等
  • 插件连接
    插件连接指插件如何连接到核心系统。通常来说,核心系统必须制定插件和核心系统的 连接规范,然后插件按照规范实现,核心系统按照规范加载即可。常见的连接机制有 OSGi CEc li pse 使用)、消息模式、依赖注入( Spring 使用),甚至使 用分布式的协议都是可以的,比如 RPC 或 HTTP Web 的方式
  • 插件通信
    插件通信指插件间的通信 。 虽然设计的时候插件间是完全解稿的,但实际业务运行过程 中,必然会出现某个业务流程需要多个插件协作,这就要求两个插件间进行通信。由于插件之间没有直接联系,通信必须通过核心系统,因此核心系统需要提供插件通信机制。 这种情况和计算机类似,计算机的CPU、硬盘、内存、网卡是独立设计的配件 ,但计算机运行过程中,CPU和内存、内存和硬盘肯定是有通信的,计算机通过主板上的总线提供了这些组件之间的通信功能。微内核的核心系统也必须提供类似的通信机制,各个插件之间才能进行正常的通信。

OSGi架构

OSGi 的全称是Open Services Gateway initiative,由于OSGi 具备动态化、热插拔、高可复用性、高效性、扩展方便等优点,它被应用到了PC上的应用开发,尤其是Eclipse这个流行软件采用OSGi标准后,OSGi更是成为首选的插件化标准,Eclipse从3.0 版本开始,抛弃了原来自己实现的插件化框架,改用了OSGi 框架

需要注意的是,OSGi是一个插件化的标准,而不是一个可运行的框架,Eclips巳采用的OSGi框架称为Equinox,类似的实现还有Apache的Felix 、Spring的SpringDM

OSGi 框架的逻辑架构图如下

架构师修炼系列【微内核架构】_架构师养成记_02

  • 模块层(Module 层)
    模块层完成插件管理功能 ,OSGi 中,插件被称为Bundle,每个Bundle是一个Java的JAR文件,每个 Bundle里面都包含一个元数据文件MANIFEST.MF,这个文件包含了Bundle的基 本信息,例如,Bundle 的名称、描述、开发商、 classpath,以及需要导入的包和输出的包,等等。OSGi核心系统会将这些信息加载到系统中用于后续使用,一个简单的MANIFEST.MF样例如下:
// MANIFEST.MF
Bundle-ManifestVersion:2
Bundle-Name:UserRegister
Bundle-SymbolicName:com.test.userregister
Bundle-Version:1.0
Bundle-Activator:com.test.UserRegisterActivator
Import-Package:org.log4j;version="2.0",
.....
Export-Package:com.test.userregister;version="1.0",
  • 生命周期层(Lifecycle)
    生命周期层完成插件连接功能,提供了执行时模块管理、模块对底层 OSGi 框架的访问,生命周期层精确地定义了bundle生命周期的操作(安装、更新、启动、停止、卸载),Bundle必须按照规范实现各个操作 ,例如:
public class UserRegisterActivator implements BundleActivator{
public void start(BundleContext context){
UserRegister.instance = new UserRegister();
}
public void stop(BundleContext context){
UserRegister.instance = null;
}
}
  • 服务层(Service层)
    服务层完成插件通信的功能。 OSGi 提供了一个服务注册的功能,用于各个插件将自己能提供的服务注册到 OSGi 核心的服务注册中心,如果某个服务想用其他服务,则直接在服务注册中心搜索可用服务就可以了,例如:
// 注册服务
public class UserRegisterActivator implements BundleActivator{
// 在start()中用BundleContext.registerService() 注册服务
public void start(BundleContext context){
context.registerService(UserRegister.class.getName(), new UserRegisterImpl(), null);
}
// 无需在stop()中注销服务,因为BUndle停止时会自动注销该bundle中已注册的服务
public void stop(BundleContext context){
}
}
// 检索服务
public class Client implements BundleActivator{
public void start(BundleContext context){
// 从服务注册表中检索间接的“服务引用”
ServiceReference ref = context.getServiceReference(UserRegister.class.getName());
// 使用“服务引用”去访问服务对象的实例
((UserRegister) context.getService(ref).register());
}
public void stop(BundleContext context){

}

}

这里的服务注册不是插件管理功能中的插件注册,这里的服务注册实际上就是一个插件通信的机制

规则引擎架构

规则引擎从结构上来看也属于微内核架构的一种具体实现,其中执行引擎可以看作微内核, 执行引擎解析配置好的业务流,执行其中的条件和规则,通过这种方式来支持业务的灵活多变,主要原因在于:

  • 可扩展 :通过引入规则引擎,业务逻辑实现与业务系统分离,可以在不改动业务系统的情况下扩 展新的业务功能
  • 易理解:规则通过自然语言描述,业务人员易于理解和操作,而不像代码那样只有程序员才能理 解和开发
  • 高效率:规则引擎系统一般提供可视化的规则定制、审批、查询及管理,方便业务人员快速配置 新的业务

规则引擎的基本架构如下图所示

架构师修炼系列【微内核架构】_OSGi架构_03

  • 开发人员将业务功能分解提炼为多个规则,将规则保存在规则库中
  • 业务人员根据业务需要,通过将规则排列组合,配置成业务流程,保存在业务库中
  • 规则引 擎执行业务流程,实现业务功能

对照微内核架构的设计关键点,我们来看看规则引擎是具体是如何实现的

  • 插件管理:规则引擎中的规则就是微内核架构的插件,引 擎就是微内核架构的内核。规则可以被引 擎加载和执行 。在规则引 擎架构中,规则一般保存在规则库中,通常使用数据库来存储
  • 插件连接:类似于程序员开发的 时候需要采用Java、C++等语言,规则引擎也规定了规则开发的语 言 ,业务人员需要基于规则语言来编写规则文件,然后由规则引擎加载执行规则文件来 完成业务功能。因此,规则引擎的插件连接实现机制其实就是规则语言
  • 插件通信:规则引擎的规则之间进行通信的方式就是数据流和事件流,由于单个规则并不需要依赖 其他规则,因此规则之间没有主动的通信,规则只需要输出数据或事件,由引擎将数据或事件传递到下一个规则

案例

目前最常用的规则引擎是开源的JBoss Drools,采用Java语言编写,基于Rete算法。Drools具有以下优点:

  • 非常活跃的社区支持,以及广泛的应用
  • 快速的执行速度
  • 与 Java Rule Engine API ( JSR-94 )兼容
  • 提供基于 Web 的 BRMS 一-Guvnor, Guvnor 提供规则管理的知识库,通过它可以实现规则的版本控制,以及规则的在线修改与编译,使得开发人员和系统管理人员可以在线管理业务规则

虽然Drools号称简单易用,但实际上其规则语言还是和编程语言比较类似的,在实际应用的时候普通业务人员面对这样的规则语言 ,学习成本和理解成本还是比较高 的,比如下面这个 样例:

package com.sample
import com.sample.DroolsTest.Message;
rule "Hello World"
when
m:Message(status==Message.HELLO, myMessage:message)
then
System.out.println(myMessage);
m.setMessage("Goodbye cruel world");
m.setStatus(Message.GOODBYE);
update(m);
end

rule "GoodBye"
when
Message(status==Message.GOODBYE, myMessage:message)
then
System.out.println(myMessage);

因此,通常情况下需要基于 Drool s 进行封装,将规则配置做成可视化的操作