SOFABoot-09-模块隔离
前言
大家好,我是老马。
sofastack 其实出来很久了,第一次应该是在 2022 年左右开始关注,但是一直没有深入研究。
最近想学习一下 SOFA 对于生态的设计和思考。
sofaboot 系列
SOFABoot-00-sofaboot 概览
SOFABoot-01-蚂蚁金服开源的 sofaboot 是什么黑科技?
SOFABoot-02-模块化隔离方案
SOFABoot-03-sofaboot 介绍
SOFABoot-04-快速开始
SOFABoot-05-依赖管理
SOFABoot-06-健康检查
SOFABoot-07-版本查看
SOFABoot-08-启动加速
SOFABoot-09-模块隔离
SOFABoot-10-聊一聊 sofatboot 的十个问题
模块化开发概述
SOFABoot 从 2.4.0 版本开始支持基于 Spring 上下文隔离的模块化开发能力。为了更好的理解 SOFABoot 模块化开发的概念,我们来区分几个常见的模块化形式:
基于代码组织上的模块化:这是最常见的形式,在开发期,将不同功能的代码放在不同 Java 工程下,在编译期被打进不同 jar 包,在运行期,所有 Java 类都在一个 classpath 下,没做任何隔离;
基于 Spring 上下文隔离的模块化:借用 Spring 上下文来做不同功能模块的隔离,在开发期和编译期,代码和配置也会分在不同 Java 工程中,但在运行期,不同模块间的 Spring Bean 相互不可见,DI 只在同一个上下文内部发生,但是所有的 Java 类还是在同一个 ClassLoader 下;
基于 ClassLoader 隔离的模块化:借用 ClassLoader 来做隔离,每个模块都有独立的 ClassLoader,模块与模块之间的 classpath 不同,SOFAArk 就是这种模块化的实践方式。
SOFABoot 模块化开发属于第二种模块化形式 —— 基于 Spring 上下文隔离的模块化。
每个 SOFABoot 模块使用独立的 Spring 上下文,避免不同 SOFABoot 模块间的 BeanId 冲突,有效降低企业级多模块开发时团队间的沟通成本。
关于 SOFABoot 模块化产生的背景,可参考文章 《蚂蚁金服的业务系统模块化 —- 模块化隔离方案》
功能简介

JVM 服务发布与引用
SOFABoot 提供三种方式给开发人员发布和引用 JVM 服务
-
XML 方式
-
Annotation 方式
-
编程 API 方式
XML 方式
服务发布
首先需要定义一个 Bean:
<bean id="sampleService" class="com.alipay.sofa.runtime.test.service.SampleServiceImpl">
然后通过 SOFA 提供的 Spring 扩展标签来将上面的 Bean 发布成一个 SOFA JVM 服务。
<sofa:service interface="com.alipay.sofa.runtime.test.service.SampleService" ref="sampleService"><sofa:binding.jvm/>
</sofa:service>
上面的配置中的 interface 指的是需要发布成服务的接口,ref 指向的是需要发布成 JVM 服务的 Bean,至此,我们就已经完成了一个 JVM 服务的发布。
服务引用
使用 SOFA 提供的 Spring 扩展标签引用服务:
<sofa:reference interface="com.alipay.sofa.runtime.test.service.SampleService" id="sampleServiceRef"><sofa:binding.jvm/>
</sofa:reference>
上面的配置中的 interface 是服务的接口,需要和发布服务时配置的 interface 一致。
id 属性的含义同 Spring BeanId。
上面的配置会生成一个 id 为 sampleServiceRef 的 Spring Bean,你可以将 sampleServiceRef 这个 Bean 注入到当前 SOFABoot 模块 Spring 上下文的任意地方。
service/reference 标签还支持 RPC 服务发布,相关文档: RPC 服务发布与引用
Annotation 方式
如果一个服务已经被加上了 @SofaService 的注解,它就不能再用 XML 的方式去发布服务了,选择一种方式发布服务,而不是两种混用。
除了通过 XML 方式发布 JVM 服务和引用之外,SOFABoot 还提供了 Annotation 的方式来发布和引用 JVM 服务。
通过 Annotation 方式发布 JVM 服务,只需要在实现类上加一个 @SofaService 注解即可,如下:
@SofaService
public class SampleImpl implements SampleInterface {public void test() {}
}
- 提示
@SofaService 的作用是将一个 Bean 发布成一个 JVM 服务,这意味着虽然你可以不用再写 <sofa:service/> 的配置,但是还是需要事先将 @SofaService 所注解的类配置成一个 Spring Bean。
在使用 XML 配置 <sofa:service/> 的时候,我们配置了一个 interface 属性,但是在使用 @SofaService 注解的时候,却没有看到有配置服务接口的地方。
这是因为当被 @SofaService 注解的类只有一个接口的时候,框架会直接采用这个接口作为服务的接口。
当被 @SofaService 注解的类实现了多个接口时,可以设置 @SofaService 的 interfaceType 字段来指定服务接口,比如下面这样:
@SofaService(interfaceType=SampleInterface.class)
public class SampleImpl implements SampleInterface, Serializable {public void test() {}
}
和 @SofaService 对应,Sofa 提供了 @SofaReference 来引用一个 JVM 服务。
假设我们需要在一个 Spring Bean 中使用 SampleJvmService 这个 JVM 服务,那么只需要在字段上加上一个 @SofaReference 的注解即可:
public class SampleServiceRef {@SofaReferenceprivate SampleService sampleService;
}
和 @SofaService 类似,我们也没有在 @SofaReference 上指定服务接口,这是因为 @SofaReference 在不指定服务接口的时候,会采用被注解字段的类型作为服务接口,你也可以通过设定 @SofaReference 的 interfaceType 属性来指定:
public class SampleServiceRef {@SofaReference(interfaceType=SampleService.class)private SampleService sampleService;
}
使用 @SofaService 注解发布服务时,需要在实现类上打上 @SofaService 注解;在 Spring Boot 使用 Bean Method 创建 Bean 时,会导致 @Bean 和 @SofaService 分散在两处,而且无法对同一个实现类使用不同的 unique id。
因此自 SOFABoot v2.6.0 及 v3.1.0 版本起,支持 @SofaService 作用在 Bean Method 之上,例如:
@Configuration
public class SampleSofaServiceConfiguration {@Bean("sampleSofaService")@SofaService(uniqueId = "service1")SampleService service() {return new SampleServiceImpl("");}
}
同样为了方便在 Spring Boot Bean Method 使用注解 @SofaReference 引用服务,自 SOFABoot v2.6.0 及 v3.1.0 版本起,支持在 Bean Method 参数上使用 @SofaReference 注解引用 JVM 服务,例如:
@Configuration
public class MultiSofaReferenceConfiguration {@Bean("sampleReference")TestService service(@Value("$spring.application.name") String appName,@SofaReference(uniqueId = "service") SampleService service) {return new TestService(service);}
}
编程 API 方式
SOFABoot 为 JVM 服务的发布和引用提供了一套编程 API 方式,方便直接在代码中发布和引用 JVM 服务,与 Spring 的 ApplicationContextAware 类似,为使用编程 API 方式,首先需要实现 ClientFactoryAware 接口获取编程组件 API:
public class ClientFactoryBean implements ClientFactoryAware {private ClientFactory clientFactory;@Overridepublic void setClientFactory(ClientFactory clientFactory) {this.clientFactory = clientFactory;}
}
以 SampleService 为例,看下如何使用 clientFactory 通过编程 API 方式发布 JVM 服务:
ServiceClient serviceClient = clientFactory.getClient(ServiceClient.class);ServiceParam serviceParam = new ServiceParam();
serviceParam.setInstance(new SampleServiceImpl());
serviceParam.setInterfaceType(SampleService.class);
serviceClient.service(serviceParam);
上面的代码中
-
首先通过 clientFactory 获得 ServiceClient 对象
-
然后构造 ServiceParam 对象,ServiceParam 对象包含发布服务所需参数,通过 setInstance 方法来设置需要被发布成 JVM 服务的对象,setInterfaceType- 来
设置服务的接口 -
最后,调用 ServiceClient 的 service 方法,发布一个 JVM 服务
通过编程 API 方式引用 JVM 服务的代码也是类似的:
ReferenceClient referenceClient = clientFactory.getClient(ReferenceClient.class);ReferenceParam<SampleService> referenceParam = new ReferenceParam<SampleService>();
referenceParam.setInterfaceType(SampleService.class);
SampleService proxy = referenceClient.reference(referenceParam);
同样,引用一个 JVM 服务只需从 ClientFactory 中获取一个 ReferenceClient ,然后和发布一个服务类似,构造出一个 ReferenceParam,然后设置好服务的接口,最后调用 ReferenceClient 的 reference 方法即可。
通过动态客户端创建的 Reference 对象是一个非常重的对象,请大家在使用的时候不要频繁创建,自行做好缓存,否则可能存在内存溢出的风险。
除了实现 ClientFactoryAware 接口用于获取 ServiceClient 和 ReferenceClient 对象,还可以使用简便的注解 @SofaClientFactory 获取编程 API,例如
public class ClientBean {@SofaClientFactoryprivate ReferenceClient referenceClient;@SofaClientFactoryprivate ServiceClient serviceClient;
}
uniqueId
有些时候,针对一个接口,我们会需要发布两个服务出来,分别对应到不同的实现。
继续前面的 sampleService 的例子,我们可能有两个 SampleService 的实现,这两个实现我们都需要发布成 SOFA 的 JVM Service,按照前面的教程,采用 XML 的方式,我们就可能用下面这种方式进行配置:
<sofa:service interface="com.alipay.sofa.runtime.test.service.SampleService" ref="sampleService1">
</sofa:service>
<sofa:service interface="com.alipay.sofa.runtime.test.service.SampleService" ref="sampleService2">
</sofa:service>
上面的服务发布没有什么问题,但是当需要引用服务的时候,就出现了问题了,例如我们使用以下配置:
<sofa:reference interface="com.alipay.sofa.runtime.test.service.SampleService" id="sampleService">
</sofa:reference>
这个 JVM 引用到底引用的是哪个 JVM 服务呢,我们无从知晓。
为了解决上面的这种问题,SOFABoot 引入了 uniqueId 的概念,针对服务接口一样的 JVM 服务,可以通过 uniqueId 来进行区分,上面的服务发布的代码我们加入 uniqueId 后,我们可以改成下面这样:
<sofa:service interface="com.alipay.sofa.runtime.test.service.SampleService" ref="sampleService1" unique-id="ss1">
</sofa:service>
<sofa:service interface="com.alipay.sofa.runtime.test.service.SampleService" ref="sampleService2" unique-id="ss2">
</sofa:service>
然后,在引用服务的时候,如果我们要使用 sampleService1 的服务,可以指定 unique-id 为 ss1,比如:
<sofa:reference interface="com.alipay.sofa.runtime.test.service.SampleService" id="sampleService" unique-id="ss1">
</sofa:reference>
如果要使用 sampleService2 的服务,可以指定 unique-id 为 ss2,比如:
<sofa:reference interface="com.alipay.sofa.runtime.test.service.SampleService" id="sampleService" unique-id="ss2">
</sofa:reference>
上面说的是在 XML 的方式中使用 uniqueId。当你用 Annotation 的方式发布 JVM 服务和引用的时候,可以通过设置 @SofaService 和 @SofaReference 的 uniqueId 属性来设置 uniqueId。
当你用编程 API 的方式发布或者引用 JVM 服务的时候,可以通过 ServiceParam 和 ReferenceParam 的 setUniqueId 方法来设置 uniqueId。
小结
希望本文对你有所帮助,如果喜欢,欢迎点赞收藏转发一波。
我是老马,期待与你的下次相遇。
相关文章:
SOFABoot-09-模块隔离
前言 大家好,我是老马。 sofastack 其实出来很久了,第一次应该是在 2022 年左右开始关注,但是一直没有深入研究。 最近想学习一下 SOFA 对于生态的设计和思考。 sofaboot 系列 SOFABoot-00-sofaboot 概览 SOFABoot-01-蚂蚁金服开源的 s…...
电池电量检测方法介绍,开路电压法、库仑积分法、内阻法
开路电压法、库仑积分法、内阻法、卡尔曼滤波法、混合法 开路电压法是目前最简单的方法,根据电池的特性得知,在电池容量与开路电压之间存在一定的函数关系,当得知开路电压时,可以初步估算电池的剩余电量。该方法精度不高…...
基于基于eFish-SBC-RK3576工控板的智慧城市边缘网关
此方案充分挖掘eFish-SBC-RK3576的硬件潜力,可快速复制到智慧园区、交通枢纽等场景。 方案亮点 接口高密度:单板集成5GWiFi多路工业接口,减少扩展复杂度。AIoT融合:边缘端完成传感器数据聚合与AI推理,降低云端…...
CSS基础知识一览
持续维护 选择器 display 常用属性 浮动 弹性布局...
《Keras 3 : AI神经网络开发人员指南》
《Keras 3 : AI神经网络开发人员指南》 开发人员指南 我们的开发人员指南深入探讨了特定主题,例如层子类化、微调或模型保存。 它们是成为 Keras 专家的最佳方式之一。 我们的大多数指南都是以 Jupyter 笔记本的形式编写的,可以在 Google Colab 中一键…...
【免费】2000-2019年各省地方财政房产税数据
2000-2019年各省地方财政房产税数据 1、时间:2000-2019年 2、来源:国家统计局、统计年鉴 3、指标:行政区划代码、地区、年份、地方财政房产税 4、范围:31省 5、指标说明:房产税是对个人和单位拥有的房产征收的一种…...
WPF 布局舍入(WPF 边框模糊 或 像素错位 的问题)
1. 什么是 WPF 布局舍入? 在 WPF 开发过程中,可能会遇到界面模糊、边框错位、文本渲染不清晰等问题。这些现象通常是由于 WPF 采用 设备无关像素(DIP, Device Independent Pixels),在不同 DPI 设置下,UI 元…...
车载以太网网络测试-21【传输层-DOIP协议-4】
目录 1 摘要2 DoIP entity status request/response(0x4001、0x4002)2.1 使用场景2.2 报文结构2.2.1 0x4001:DoIP entity status request2.2.2 0x4002:DoIP entity status response 3 Diagnostic power mode information request/…...
机器学习——KNN数据集划分
一、主要函数 sklearn.datasets.my_train_test_split() 该函数为Scikit-learn 中用于将数据集划分为训练集和测试集的函数,适用于机器学习模型的训练和验证。以下是详细解释: 1、函数签名 train_test_split(*arrays, # 输入的数据…...
Pytest基础使用
概述 Pytest是Python里的一个强大的测试框架,灵活易用,可以进行功能,自动化测试使用,可以与Requests,Selenium等进行结合使用,同时可以生成Html的报告。 一、Pytest的基本使用 在未指定Pytest的配置文件时,会对以下文件进行执行: test_*.py,如:test_1.py*_test.py…...
Grid 布局实现三栏布局
使用 CSS Grid 布局实现三栏布局(左右固定 100px,中间自适应)的核心原理是通过网格模板精确控制列宽分配。以下是具体实现方法及优化技巧: 一、基础实现 父容器设置 为外层容器添加 display: grid 使其成为网格容器,并通过 grid-template-columns 定义列宽 css .contain…...
一条sql语句在mysql中的执行流程(Mysql基础架构)
mysql基础架构 MySQL 主要分为 Server 层和 存储引擎层: Server 层:主要包括 连接器、查询缓存、分析器、优化器、执行器等,所有跨存储引擎的功能都在这一层实现,比如存储过程、触发器、视图,函数等,还有一…...
Spring AI Alibaba ChatModel使用
一、对话模型(Chat Model)简介 1、对话模型(Chat Model) 对话模型(Chat Model)接收一系列消息(Message)作为输入,与模型 LLM 服务进行交互,并接收返回的聊天…...
基于FPGA频率、幅度、相位可调的任意函数发生器(DDS)实现
基于FPGA实现频率、幅度、相位可调的DDS 1 摘要 直接数字合成器( DDS ) 是一种通过生成数字形式的时变信号并进行数模转换来产生模拟波形(通常为正弦波)的方法,它通过数字方式直接合成信号,而不是通过模拟信号生成技术。DDS主要被应用于信号生成、通信系统中的本振、函…...
k8s高可用集群安装
一、安装负载均衡器 k8s负载均衡器 官方指南 1、准备三台机器 节点名称IPmaster-1192.168.1.11master-2192.168.1.12master-3192.168.1.13 2、在这三台机器分别安装haproxy和keepalived作为负载均衡器 # 安装haproxy sudo dnf install haproxy -y# 安装Keepalived sudo yum …...
WPF Reactive 数据绑定
文章目录 Combox 绑定List-通过枚举绑定方法一:方法二:Button 绑定TextBlock绑定NumericUpDown绑定Expander绑定checkbox绑定NumericUpDownCombox 绑定List-通过枚举绑定 方法一: ViewControl using Avalonia; using Avalonia.Controls; using Avalonia.Markup.Xaml; usin…...
WSL 环境桥接与雷达通信配置笔记
作者: DWDROME 维护时间: 2025-03-22 参考文章:Windows子系统(WSL)通过桥接网络实现被外部局域网主机直接访问 WSL 环境桥接与雷达通信配置笔记 环境说明 Windows 11 专业版(启用 Hyper-V)WSL2 Ubuntu 20.04物理网线(…...
3DMAX曲线生成器插件CurveGenerator使用方法
1. 脚本功能简介 3DMAX曲线生成器插件CurveGenerator是一个用于 3ds Max 的样条线生成工具,用户可以通过简单的UI界面输入参数,快速生成多条样条线。每条样条线的高度值随机生成,且可以自定义以下参数: 顶点数量:每条…...
六十天前端强化训练之第二十六天之Vue Router 动态路由参数大师级详解
欢迎来到编程星辰海的博客讲解 看完可以给一个免费的三连吗,谢谢大佬! 目录 一、知识讲解 1. Vue Router 核心概念 2. 动态路由参数原理 3. 参数传递方案对比 二、核心代码示例 1. 完整路由配置 2. 参数接收组件 3. 导航操作示例 三、实现效果示…...
Model Context Protocol:下一代AI系统集成范式革命
在2023年全球AI工程化报告中,开发者面临的核心痛点排名前三的分别是:模型与业务系统集成复杂度(58%)、上下文管理碎片化(42%)、工具调用标准化缺失(37%)。传统API集成模式在对接大语言模型时暴露明显短板:RESTful接口无法承载动态上下文,GraphQL缺乏工具编排能力,gR…...
Java多线程与高并发专题——Future 是什么?
引入 在上一篇Callable 和 Runnable 的不同?的最后,我们有提到和 Callable 配合的有一个 Future 类,通过 Future 可以了解任务执行情况,或者取消任务的执行,还可获取任务执行的结果,这些功能都是 Runnable…...
DeepSeek本地搭建
1. 软件下载安装 Miniconda Miniconda下载地址 选择对应的版本下载,此处下载如下版本 Python 3.10 conda 25.1.1 安装完成后,配置环境变量,打开cmd命令窗口验证 Python Python的版本为 3.10 PyTorch PyTorch下载地址 后面通过命令下…...
维普AIGC降重方法有哪些?
在学术写作和论文创作中,重复率过高是许多人面临的一大难题。随着科技的发展,维普 AIGC 为我们提供了一系列有效的降重方法。那么,维普AIGC降重方法有哪些呢?接下来就为大家详细介绍。 语义理解与改写 维普 AIGC 具备强大的语义理…...
设计模式之命令模式:原理、实现与应用
引言 命令模式(Command Pattern)是一种行为型设计模式,它将请求封装为对象,从而使你可以用不同的请求对客户进行参数化。命令模式支持请求的排队、记录日志、撤销操作等功能。本文将深入探讨命令模式的原理、实现方式以及实际应用…...
2025年十大AI工具对比
2025年十大AI工具对比 以下是2025年各大AI工具的详细对比,涵盖性能、功能、用户评价等方面,并以表格形式呈现。数据来源于多个权威来源,确保信息全面且准确。 对比表格 排名AI工具名称主要功能性能特点用户评价适用场景1DeepSeek多模态AI、…...
100道C#高频经典面试题及答案解析:C#程序员面试题库分类总结
分类一:C#基础语法 1. 值类型与引用类型的核心区别? 答案: 存储位置:值类型存栈/堆内联,引用类型存堆赋值方式:值类型复制内容,引用类型复制地址示例类型:int(值类型&…...
南京审计大学:《 面向工程审计行业的DeepSeek大模型应用指南》.pdf(免费下载)
大家好,我是吾鳴。 今天吾鳴要给大家分享的是由南京审计大学出品的《面向工程审计行业的DeepSeek大模型应用指南》,这份报告与《面向审计行业DeepSeek大模型操作指南》不同,这份报告更多的讲述DeepSeek怎么与工程审计行业结合,应该…...
DeepSeek AI大模型工作机制及未来方向
DeepSeek模型作为一款先进的人工智能模型,其工作原理结合了深度学习的前沿技术与工程优化策略,以下是其核心工作机制的分步解析: 1. 模型架构:基于Transformer的演进 - 核心结构:采用多层Transformer解码器堆叠&am…...
第十七章:Future Directions_《C++ Templates》notes
Future Directions 核心重难点:示例代码: 设计题多选题答案设计题详解 核心重难点: 泛型非类型模板参数 允许任意类型作为非类型模板参数(如template<typename T, auto N>)需解决类型推导和链接问题 编译期控制…...
NVIDIA Dynamo源码编译
Ref https://github.com/PyO3/maturin Rust 程序设计语言 代码库: https://github.com/ai-dynamo/dynamo https://github.com/ai-dynamo/nixl dynamo/container/Dockerfile.vllm 相关whl包 官方提供了4个whl包 ai_dynamo # 这个包ubuntu 22.04也可以用&…...
