文章目录

  • 十分钟搞懂系列
  • 什么是微内核架构?
  • 如何实现微内核架构?
  • 总结

十分钟搞懂系列

序号 标题 链接
1 10分钟带你彻底搞懂企业服务总线 https://blog.csdn.net/belongtocode/article/details/119487731
2 10分钟带你彻底搞懂微内核架构 https://blog.csdn.net/belongtocode/article/details/119107837
3 10分钟带你彻底搞懂服务限流和服务降级 https://blog.csdn.net/belongtocode/article/details/119107785
4 10分钟带你彻底搞懂负载均衡 https://blog.csdn.net/belongtocode/article/details/118977839
5 10分钟带你彻底搞懂集群容错和服务隔离 https://blog.csdn.net/belongtocode/article/details/118968771
6 10分钟带你彻底搞懂注册中心 https://blog.csdn.net/belongtocode/article/details/118639474
7 10分钟带你彻底搞懂RPC架构 https://blog.csdn.net/belongtocode/article/details/118639448

在日常开发过程中,我们经常会遇到这样的需求:针对某个业务场景,我们希望在系统中添加一种新的处理逻辑,但又不想对现有的系统造成太大的影响。从架构设计上讲,这是一种典型的系统扩展性需求。

针对这样的扩展性需求,本质上开发人员想要的是一种类似插件化的架构体系,调用者通过一个插件工厂获取想要的插件,而插件工厂则基于配置动态创建对应的插件,这样整体系统就像搭积木一样可以进行动态的组装。

基于插件化系统,我们往现有系统中添加新的业务逻辑时,就只需要实现一个新的插件并替换老的插件即可,系统的扩展性得到了很好的保证。

那么如何实现这样的插件系统呢?微内核(MicroKernel)架构就是业界主流的实现方案。

什么是微内核架构?

微内核架构包含两部分组件,即内核系统和插件。

这里的内核系统用来定义插件的实现规范,并管理着插件的生命周期。而各个插件是相互独立的组件,各自根据实现规范完成某项业务功能,并嵌入到内核系统中。

显然,基于微内核架构,当面对系统中的某个组件需要进行修改时,我们要做的只是创建一个新的组件并替换旧组件,而不需要改变原有组件的实现方式,更不需要调整整个系统架构。

那么这里的插件具体指的是什么呢?

这就需要我们引入一个概念,即 SPI(Service Provider Interface),也就是服务提供接口。你可以理解为,SPI 就是应对系统扩展性的一个个扩展点,也是我们对系统中所应具备的扩展性的抽象。

插件化实现机制说起来简单,做起来可不容易。我们要考虑两方面内容。

一方面,我们要梳理系统的变化并把它们抽象成 SPI 扩展点。另一方面,当我们实现了这些 SPI 扩展点之后,就需要构建一个能够支持这种可插拔机制的具体实现,从而提供一种 SPI 运行时环境。

那么接下来,我们就来一起讨论微内核架构的具体技术体系怎么搭建,进而实现我们需要的插件系统。

如何实现微内核架构?

微内核架构本质上只是为我们提供了一种架构模式,并没有规定具体的实现方式,所以原则上我们也可以提供一套满足自身要求的实现方案。但是,我们不想重复造轮子。

幸好,JDK 已经为我们提供了微内核架构的一种实现方式,这种实现方式针对如何设计和实现 SPI 提出了一些开发和配置上的规范。

对于 SPI 的实现者而言,具体有三个步骤。

对于 SPI 而言,我们需要设计一个服务接口,然后根据业务场景提供不同的实现类。然后在 Java 代码工程的 META-INF/services 目录中创建一个以服务接口命名的文件,并配置对应的想要使用的实现类。在代码工程中执行这些步骤,最终我们得到了一个包含 SPI 类和配置的 jar 包。

而对于 SPI 的使用者,就可以通过 jar 包中 META-INF/services/ 目录下的配置文件找到具体的实现类名并进行实例化。

上图中的后面两个步骤实际上都是为了遵循 JDK 中 SPI 的实现机制而进行的配置工作。

接下来,我就通过简单的代码示例来给你演示一下这些步骤。

让我们来模拟这样一个应用场景,一般业务系统中都会涉及日志组件,我们希望对业界主流的日志工具做一层包装,以便支持日志组件的灵活应用。

那么,基于 SPI 的约定,我们将创建一个单独的工程 log-spi 来存放服务接口,并给出接口定义,请注意这个服务接口的完整类路径为 com.spi.LogProvider,接口中只包含一个记录 info 日志的简单示例方法。

package com.spi;public interface LogProvider {
// 记录 Info 日志
public void info(String info);
}

假设系统在设计之初使用的是 log4j 日志库。然后我们需要实现这个服务接口,这里创建另一个代码工程 log-log4j 用来提供基于 log4j 日志库的实现,请注意,这个实现类的名称是 Log4jProvider。

public class Log4jProvider implements LogProvider{@Override
public void info(String info){
System.out.println("Log4j:” + info);
}
}

接下来的这个步骤很关键,在这个代码工程的 META-INF/services/ 目录下需要创建一个以服务接口完整类路径命名的文件,文件的内容就是指向该接口所对应的实现类。显然,当前的这个实现类就是前面创建的 Log4jProvider。

最后,我们需要创建一个外部工程 log-consumer 来调用服务接口,首先需要将 log-log4j 所生成的 jar 包添加到这个外部工程中的类路径中。然后,我们使用 JDK 中 ServiceLoader 工具类来完成对 LogProvider 实例的加载。

在这里,我们通过 ServiceLoader.load 方法获取所有的 LogProvider 实例,然后遍历这些实例并调用服务接口方法。

import java.util.ServiceLoader;
import com.spi.LogProvider;public class Main {
public static void main(String[] args) {ServiceLoader<LogProvider> loader = ServiceLoader.load(LogProvider.class);for (LogProvider provider : loader) {
System.out.println(provider.getClass());
provider.info(“testInfo”);
}
}
}

运行这段代码,我们会得到系统的输出。可以看到这里获取的是针对 log4j 的 Log4jProvider 类中的具体方法实现,表示整个 SPI 实例的加载过程是正常的。

class com.spi.Log4jProvider
Log4j:testInfo

请注意,在上面这个 Main 函数中,我们并没有引入任何与 Log4jProvider 相关的包结构,但在运行过程中,却实现了对 Log4jProvider 类的动态调用,这是怎么回事呢?

这就是微内核架构的核心特征,对组件之间的依赖关系进行了解耦,从而确保了系统的扩展性。

现在,我们再来考虑这样一种场景。随着工具的更新或者架构的调整,我们需要提供一套基于 logback 日志库的日志实现来替换现有的基于 log4j 的方案。

当然,我们可以重构原有代码来达成这个目标。但基于扩展性考虑,更好的办法是提供另一个 SPI 实例。这样,我们就可以创建新的代码工程 log-logback,并完成对 LogProvider SPI 接口的实现。请注意,这次的实现类的名称是 LogbackProvider。

public class LogbackProvider implements LogProvider {@Override
public void info(String info){
System.out.println("Logback:” + info);
}
}

同样,我们需要在这个代码工程的 META-INF/services/ 目录下创建一个配置文件,并指向新创建的 LogbackProvider 类。

接下来我们把 log-logback 所生成的 jar 包也添加到外部工程的类路径中,完成这些操作之后,我们再来执行前面的 main 函数,得到的就是来自 Log4jProvider 和 LogbackProvider 类中的输出结果。

class com.spi.Log4jProvider
Log4j:testInfo
class com.spi.LogbackProvider
Logback:testInfo

当然,你可以根据需要提供任何 LogProvider 接口的实现类并动态集成到系统的执行流程中。

不过要注意的是,无论是添加、替换还是移除具体的 SPI 实现,对于原有的 log-consumer 工程而言,我们并没有做任何的代码调整。

这就满足了我们在开篇时提到的扩展性设计理念,就是在现有系统中添加新的组件时,不会对现有系统造成太大的影响。

总结

以上就是这节课的全部内容了。

我们明确了微内核架构模式是实现系统扩展性的有效手段,在 Dubbo、ShardingSphere、Skywalking 等主流的开源框架中都有广泛应用。

而 JDK 提供的 SPI 机制以及 ServiceLoader 工具类为我们实现微内核架构提供了技术方案,帮助我们更好地把这一架构模式应用到了日常开发工作中。

最后,我想给你留一道思考题:想要使用 JDK 中提供的 SPI 机制来实现微内核架构,开发人员需要完成哪些步骤呢?

参考文章:
整理于极客时间每日一课对应文章

10分钟带你彻底搞懂微内核架构相关推荐

  1. 10分钟带你彻底搞懂服务限流和服务降级

    文章目录 十分钟搞懂系列 服务限流 计数器法 滑动窗口法 漏桶算法 令牌桶算法 服务降级 十分钟搞懂系列 序号 标题 链接 1 10分钟带你彻底搞懂企业服务总线 https://blog.csdn.n ...

  2. 10分钟带你彻底搞懂负载均衡

    文章目录 十分钟搞懂系列 负载均衡是如何保证软件系统的生产部署的? 负载均衡分发策略 请求由谁来分发? 服务器端负载均衡器 客户端负载均衡 请求分发到哪去? 静态负载均衡算法 动态负载均衡算法 十分钟 ...

  3. 8分钟带你深入浅出搞懂Nginx

    8分钟带你深入浅出搞懂Nginx Nginx是一款轻量级的Web服务器.反向代理服务器,由于它的内存占用少,启动极快,高并发能力强,在互联网项目中广泛应用. 架构图 上图基本上说明了当下流行的技术架构 ...

  4. 原码一位乘法器设计_十分钟带你彻底搞懂原码、反码、补码

    点击上方"程序员大白",选择"星标"公众号 重磅干货,第一时间送达 编辑 | 程序员大白公众号来源丨https://www.cnblogs.com/zhangz ...

  5. 泛型类有什么作用_3 分钟带你彻底搞懂 Java 泛型背后的秘密

    优质文章,及时送达 作者 | 的一幕 来源 | www.jianshu.com/p/dd34211f2565 这一节主要讲的内容是java中泛型的应用,通过该篇让大家更好地理解泛型,以及面试中经常说的 ...

  6. 【CSS】5分钟带你彻底搞懂 W3C IE 盒模型

    前言 大家好,我是HoMeTown,CSS是作为前端必有技术栈之一,但是有很多同学其实对CSS的盒模型都不是很了解,今天想聊一下Css盒子模型. 盒模型是什么 首先当一个Document对进行布局(l ...

  7. java编程石头剪刀布图片_石头、剪刀、布!10分钟带你打开深度学习大门,代码已开源...

    原标题:石头.剪刀.布!10分钟带你打开深度学习大门,代码已开源 沉沉 发自 宇宙中心 量子位 出品 | 公众号 QbitAI 深度学习技术的不断普及,越来越多的语言可以用来进行深度学习项目的开发,即 ...

  8. 怎么用Python写出随时间变化的字_面试必备 | 带你彻底搞懂 Python 生成器

    文章转载地址:面试必备 | 带你彻底搞懂 Python 生成器. 写在之前 Python 的高级语言特性一直是我们学习 Python 的一个难点,大部分人并没有做到熟练的掌握,甚至去学习它都感觉很困难 ...

  9. proe常用c语言语句,带你轻松搞懂Proe条件语句

    原标题:带你轻松搞懂Proe条件语句 本文通过几个简单的例子介绍Proe中的条件语句,希望对你能有所帮助.Proe中使用的IF条件语句和C语言中的IF语句原理是一样的,其结构稍有差别.首先我们了解一下 ...

最新文章

  1. 打包、压缩、文件查找、通配符
  2. nosql和rdnms_用于SaaS和NoSQL的Jdbi
  3. 谈谈阿里所谓的——要性
  4. 算法学习之路|最小生成树——prime算法
  5. 英超必way体育:曼城6-3曼联,帽子戏法太厉害了
  6. 点聚AIP电子签章在Chrome、Edge新内核、360系列、FireFox、IE、Opera等浏览器中实现网页内嵌效果案例(一)
  7. css 实现一个尖角_css中尖角的制作实例方法总结
  8. 安装SQL 2000 企业版
  9. 数学建模-模糊综合评价分析法原理笔记
  10. Thrift入门学习
  11. thingJS模模搭(campusbuilder/momoda)及3dsmax插件遇到的坑
  12. 手把手教你使用--常用模块--HC05蓝牙模块,无线蓝牙串口透传模块,(实例:手机蓝牙控制STM32单片机点亮LED灯)
  13. 软件工程面向对象分析
  14. Android实现朋友圈的评论和回复
  15. 计算机北大核心期刊不要审稿费,这些核心医学期刊不收取审稿费(建议收藏)...
  16. 全面解析大数定律:大数定律实现超额增长!
  17. [已修复] CredSSP 加密 Oracle 修复
  18. 付子玉:丁香园医疗领域图谱的构建与应用
  19. redis-setnx-实现原理
  20. pyspark特征工程常用方法(一)

热门文章

  1. 学校计算机社团目标,电脑社团活动计划
  2. Unity AR小游戏(玩具小车)踩坑记
  3. 【2023亲测有效】Pandownload 归来!加速效果极佳!
  4. 01Node.js入门+留言本实操
  5. 微软下载中心使用Silverlight搜索
  6. Mathorcup数学建模竞赛第六届-【妈妈杯】B题:小区车位分布的评价和优化模型(附特等奖获奖论文和Java代码)
  7. C1模拟试卷的一个算法题
  8. PWN-CTF:gef工具安装
  9. linux设置sfq队列参数,Linux内核中流量控制(5)
  10. 力扣 345. 反转字符串中的元音字母