Nop 平台核心源码阅读导引
Nop 平台核心引擎的实现代码都很简短,一般模板的核心代码量都是 5000 行左右的量级,只有 ORM 比较复杂一些,1 万多行。虽然代码很短,实际实现的功能特性却很多,要把所有细节设计都介绍到,文档量还是不小。建议有问题可以先查看源码,核心特性都有单元测试支持,可以通过调试单元测试来学习源码(直接在关键类中加断点,然后沿着堆栈向上看)。
Nop 平台所有的设计都非常简单直接,一般核心代码集中在少数几个类中。
一. 可逆计算核心原理
ResourceComponentManager 平台统一的 DSL 模型加载入口
DefaultVirtualFileSystem 自动扫描 classpath 下所有
_vfs
目录中的文件,构成一个虚拟文件系统,并自动识别 delta 定制路径ResourceLoadingCache 根据虚拟文件路径缓存解析结果
ResourceDependsManager 跟踪模型解析过程中发现的模型文件依赖关系,实现方式类似 vue 组件的动态依赖追踪,当文件被修改时,自动使得所有依赖该文件的解析结果失效
DslModelParser 根据 XDef 元模型配置,使用 DslBeanModelParser 将 XML 解析为 DSL 模型对象
DslNodeLoader 和 XDslExtender 在 DslModelParser 内部使用,加载资源文件,执行可逆计算理论中的 x-extends 算法,动态合成 XNode 节点对象
DeltaMerger 和 DeltaDiffer 实现可逆计算理论中的 x-extends 算法和 x-diff 算法
DslModelToXNodeTransformer 根据 XDef 元模型,将 DSL 模型对象转换为 XNode 节点
二. NopXLang
XLangXLang 语言编译器的使用入口
XplCompilerXML 格式的 Xpl 模板语言的编译器
XLangParseTreeParser/XLangASTBuildVisitor 根据 antlr 自动生成的 XScript 脚本语言解析器,并自动将 Antlr 的 ParseTree 转换为 XLangAST 抽象语法树节点
XplLibTagCompilerXpl 模板语言中的标签库编译器
SimpleExprParser 简单的嵌入表达式的解析器,不支持函数定义和复杂语句
LexicalScopeAnalysis 对抽象语法树进行词法作用域分析,并执行宏函数
BuildExecutableProcessor 将抽象语法树节点转换为可执行的 IExecutableExpression 可执行解释函数接口
XDefinitionParserXDef 元模型解析器
DslNodeLoader 解析 XML 文件,执行差量合并,合成得到最终的 XNode
XDslValidator 根据 XDef 元模型,验证 XNode 的合法性
DslModelParser 根据 XDef 元模型,解析 XNode 得到 DSL 模型对象
ObjMetaToXDef/XDefToObjMeta 实现 XDefinition 元模型和 ObjMeta 元数据模型之间的相互转换
DslModelToXNodeTransformer 将 DSL 模型对象反向序列化为 XNode
DslXNodeToJsonTransformer 根据 XDef 元模型,将 DSL 对应的 XNode 节点转换为 JSON 对象
CompactXNodeToJsonTransformer/CompactJsonToXNodeTransformer 在没有 XDef 元模型的情况下,通过约定 type 和 body 等少量属性,实现紧凑格式的 XNode 与 JSON 之间的相互转换
三. NopCodeGen
XCodeGenerator 代码生成器的核心入口
CodeGenTaskmvn install 时通过 exec-maven-plugin 插件调用的代码生成器入口
CliGenCommandnop-cli 命令行工具调用代码生成器的入口函数,内部使用 XCodeGenerator 实现
AstGrammarBuilder 分析 g4 语法定义,转换为 AstGrammar 模型结构。根据 ParseTree 自动构造 AST 语法树时会使用 AstGrammar 所提供的信息
JdkJavaCompilerAOP 代码生成时使用 JDK 内置的 java 编译器来编译 Java 文件为字节码
JavaObjMetaParser 利用 janino 解析器,将后缀名为 xjava 的文件解析为 ObjMeta 对象。EqlAST 和 XLangAST 等生成抽象语法树结构时都使用了这一机制。
四. NopIoC
BeanContainerImpl 外部访问 IoC 容器的核心接口,负责管理所有的 bean
AppBeanContainerLoader 执行 bean 的自动发现功能。扫描所有模块下的 autoconfig bean,以及满足
beans/app-*.beans.xml
模式的 bean 文件BeanContainerBuilder 根据收集到的所有 bean 配置,构建 BeanContainer 对象
BeanConditionEvaluator 检查 ioc:condition 等动态条件,处理 alias 映射,剔除所有不满足条件的 bean
BeanDefinitionBuilder 处理
@Inject
注解等自动编配属性,初始化所有 property 的 valueResolverAopBeanProcessor 将 bean 的创建类替换为 Aop 增强后的派生类,并注入 interceptor 配置
ConfigExpressionProcessor 识别 bean 属性配置中的
@cfg:nop.server.port
和${nop.server.port}
这种配置表达式,将它们转换为 IValueResolver
五. NopConfig
DefaultConfigProvider 外部使用配置管理引擎的核心入口
ConfigStarter 配置管理引擎的核心逻辑,在这里详细定义了配置项加载顺序和覆盖关系
RouterConfigSource 实现灰度配置发布
NacosConfigService 基于 Nacos 实现从远程配置中心获取配置,并实现配置实时更新
六. NopDao
DaoProvider 外部使用的获取 IEntityDao 的统一入口
DialectManager 统一管理数据库方言模型
JdbcTemplateImpl 类似于 Spring 中的 JdbcTemplate,对 JDBC 访问请求的模板模式封装。内置数据缓存和多数据源支持
JdbcTransactionFactory 对数据库事务的封装,支持柔性事务和异步处理
JdbcDataSet 通用的 DataSet 结构封装,凡是表格类型的数据全部封装为统一的 IDataSet 接口
七. NopORM
OrmSessionImplORM 引擎的核心功能入口,负责所有实体状态切换和一级缓存管理
OrmSessionEntityCache 一级缓存的实现。从数据库中获取的所有数据都存放在一级缓存中。
OrmEntity 实体对象的基类,记录实体和属性的修改状态
EntityPersisterImpl 单实体对象的增删改查处理,识别全局缓存和多租户,内部使用 EntityPersisterDriver 来最终访问外部存储
CollectionPersisterImpl 一对多集合对象的增删改查处理,识别全局缓存和多租户
JdbcEntityPersistDriver 单实体对象的 JDBC 持久化实现
JdbcCollectionPersistDriver 一对多集合对象的 JDBC 持久化实现
OrmBatchLoadQueue 批量加载优化,解决 JPA 长期存在的 N+1 问题
JdbcQueryExecutor 利用 EqlCompiler 将 EQL 对象查询语法转换为 SQL 语句并执行
EqlCompiler 将 EQL 语法编译为 SQL 语句,使用 EqlTransformVisitor 将对象属性关联转换为表关联,AstToSqlGenerator 根据转换后的 AST 语法树生成 SQL 语句
CascadeFlushersession.flush 的时候会递归检查所有实体是否被修改,并自动生成对应的增删改查操作,放入 BatchActionQueue 执行队列,后者最终会调用 EntityPersister
OrmTemplate 类似于 Spring 中 HibernateTemplate 的模板模式封装
EntityDao 在 OrmTemplate 的基础上,针对单个实体类的封装,功能类似于 JpaRepository 的加强版。一般业务开发中优先使用这个接口
SqlLibManager 类似 MyBatis 的 EQL 和 SQL 语句管理器。SqlLibInvoker 负责将 Mapper 接口方法调用转化为对 SqlLibManager 方法的调用
八. NopGraphQL
GraphQLEngine 外部使用的 GraphQL 引擎核心入口
GraphQLDocumentParser 手工编写的 GraphQL 语言解析器
GraphQLSelectionResolver 验证前端发过来的 GraphQL 查询语句中的元素都具有合法定义
RpcSelectionSetBuilderREST 调用模式下,如果前端不传送
@selection
参数,则这里自动添加所有非 lazy 的字段作为 selectionGraphQLExecutor 任务派发和结果选择的具体执行逻辑
BizObjectManager 使用 BizObjectBuilder 动态组装 BizObject 业务对象。将 BizObjet 上的方法映射为 GraphQLOperation,将 BizObject 的属性结构映射为 GraphQLObjectDefinition。
BizObjectBuilder 将 XMeta 文件、XBiz 文件中的信息,以及 BizModel Java 类中的信息合成在一起,构成有一个完整的 BizObject 业务对象。
ReflectionBizModelBuilder 和 ReflectionGraphQLTypeFactory 使用反射机制,根据 Java 类上的
@BizModel/@BizQuery
等注解构造 GraphQL 操作定义和类型定义ObjMetaToGraphQLDefinition 将 xmeta 元数据定义转换为 GraphQL 类型定义
BizModelToGraphQLDefinition 将 xbiz 模型定义转换为 GraphQL 操作定义
GraphQLActionAuthChecker 精确到字段级别的权限约束
九. NopRPC
ClusterRpcClient 分布式 RPC 客户端调用的核心逻辑
ClusterRpcProxyFactoryBean/RpcInvocationHandler 将 RPC 接口适配到 ClusterRpcClient 对象上的方法
HttpRpcService 基于 http 协议实现 RPC 调用
MessageRpcClient 基于单向发送和接收的消息队列实现 RPC 调用
SentinelFlowControlRunner 集成 Sentinel 实现熔断限流
LoadBalanceServerChooser 通过负载均衡算法选择服务实例
RouteServiceInstanceFilter 识别消息头中的 nop-svc-route 配置,实现服务的灰度发布
十. NopGrpc
GrpcServer 启动 gRPC 服务器,将 GraphQL 服务转换为 gRPC 服务对外暴露
GraphQLServerCallHandler 将 gRPC 的服务端处理器转换为对 GraphQLEngine 的调用
ServiceSchemaManager 根据 GraphQL 类型定义,动态生成 protobuf 格式的编解码器
GraphQLToApiModel 将 GraphQL 服务定义转换为 api.xdef 元模型定义的 Api 模型
十一. NopReport
ReportEngine 外部访问报表引擎的核心入口
ExcelWorkbookParser 将 xlsx 文件解析为 ExcelWorkbook 对象,直接解析 xlsx 文件中的 XML,不使用 Apache POI 包。
ExcelToXptModelTransformer 将 ExcelWorkbook 转换为报表模型对象,
XptModelInitializer 分析 XptModel 中父子单元格的关联关系,产生的分析结果保存在 XptCellModel 中
ExcelFormularParser
解析 Excel 公式语法,将它转换为 ReportExpr
ReportExpressionParser 为普通的表达式引擎增加报表层次坐标语法支持
ExpandedSheetGenerator 执行报表引擎的核心逻辑,将 ExcelSheet 模板动态展开为 ExpandedSheet,内部使用 TableExpander 实现表格展开
TableExpander/CellRowExpander/CellColExpander 执行中国式报表的行列对称展开算法,构造 ExpandedTable 对象
DynamicReportDataSet 在报表展开过程中,提供数据集封装,简化层次坐标和数据集数据转换操作
CellCoordinateHelper
层次坐标表达式的核心执行逻辑
ExcelTemplate 将展开后的 ExpandedSheet 导出为 Excel 文件,直接生成 xml 和 xlsx 文件,不使用 POI 库
HtmlTemplate 将展开后的 ExpandedSheet 导出为 Html 文件
十二. NopRule
RuleManager 外部使用规则引擎的核心入口
ExecutableRule 和 ExecutableMatrixRule 决策树和决策矩阵的具体执行逻辑
RuleExprParser 手工编写的类似于 FEEL(Friendly Enough Expression Language)的表达式语法解析器
DaoRuleModelLoader 和 DaoRuleModelSaver 将规则模型保存到 nop_rule_definition 表中
RuleExcelModelParser
从 xlsx 文件中解析规则模型,支持决策树和决策矩阵
RuleServiceImpl 将规则引擎功能对外暴露为 GraphQL 和 REST 服务
十三. NopWorkflow
WorkflowManagerImpl 外部访问工作流引擎的核心入口
WorkflowImpl 从 WorkflowManager 中创建或者加载的工作流对象,它内部调用 WorkflowEngine 实现功能
WorkflowEngineImpl 工作流引擎的核心实现逻辑
DaoWorkflowStore 工作流的持久化存储
WfModelAnalyzer 分析工作流模型配置的有效性,并剔除回退分支,构建出 DAG 有向无环图模型
DaoWfActorResolver 适配外部用户、角色、部门管理和工作委托机制
WorkflowServiceImpl 提供对外的 GraphQL 服务和 REST 服务
十四. NopBatch
BatchTaskBuilder 负责创建 BatchTask 的工厂类。它负责组织 skip/retry/transaction/process/listener 的处理顺序
BatchTask 批处理任务的核心逻辑,多线程并行执行,每个线程上分批次执行,每次处理一个 chunk
RetryBatchConsumer 为 chunk 处理增加失败重试逻辑
BatchProcessorConsumer 逐条处理输入数据,并收集所有的输出数据到列表结构中,然后统一调用一次下游的 consumer
PartitionDispatchLoader 根据业务数据特征,将数据派发到不同的数据分区队列中进行处理
ResourceRecordLoader 通用的数据文件加载器
ResourceRecordConsumer 通用的数据文件输出机制
BatchGenLoader 压力测试中使用的测试数据生成器,根据配置动态生成具有指定数据分布的测试数据
十五. NopJob
DefaultJobScheduler 外部使用 Job 调度引擎的核心入口
TriggerBuilder 定时触发器的构造逻辑
CalendarBuilderCalendar 表达需要被的假期和指定时间区间
TriggerExecutorImplJob 定时调度的核心执行逻辑
十六. NopAutoTest
JunitAutoTestCase 需要录制回放支持的单元测试从这个基类继承。注解中标注的 NopJunitExtension 提供了具体的与 Junit 集成支持
JunitBaseTestCase 不需要录制回放功能,但是需要使用 NopIoC 注入 bean 的单元测试从这个基类继承
BaseTestCase 最简单的,不需要 NopIoC 自动注入的测试用例可以从这个基类继承,它提供给了获取资源文件数据的一些便捷方法
AutoTestCaseDataBaseInitializer 根据 input 目录下录制的数据自动初始化内存数据库
AutoTestCaseDataSaver 将通过 AutoTestOrmHook 收集到的对数据库修改的内容保存到 output 目录下
AutoTestCaseResultChecker 单元测试执行完之后,自动运行 checker 来检查执行结果与录制的数据内容是否匹配
AutoTestMatchChecker 使用 nop-match 模块提供的前缀引导匹配语法来校验数据模式
AutoTestVars 单元测试运行过程中产生的随机数等每次运行都变化的量需要在这个集合中注册,这样在录制的时候会把它们替换为变量名
版权声明: 本文为 InfoQ 作者【canonical】的原创文章。
原文链接:【http://xie.infoq.cn/article/f467c4dfc0897c1dbb8e113ed】。
本文遵守【CC-BY 4.0】协议,转载请保留原文出处及本版权声明。
评论