天行有常,不为尧存,不为桀亡。——荀子《天论》
xx包名为特殊的客户包名
在核心数据结构中,有一类比较特殊的配置就是options
配置,该配置是一个JsonObject
的数据格式,但是在Origin X
中他存在一些特殊的配置信息实现配置扩展,这些配置并非标准,但可以作为Origin X
中的一种约定,Options的配置主要对应于I_SERVICE
表中的serviceConfig
字段。
Todo配置在任务配置中,每天会有Daily的任务运行,从UCMDB拉取相关的配置项数据,并且生成确认单,并且将确认单和生命周期管理器关联(ITSM工作流?CMDB内部工作流),它的配置如下:
{
"plugin.todo": "cn.originx.xxx.extension.AspectTodo"
}
在系统的添加、删除、查询修改过程中,每一个操作都会在系统底层生成相关的变更历史,存储在:X_ACTIVITY, X_ACTIVITY_CHANGE
表中,它记录了某个用户对于配置项的所有操作,它的核心配置如下:
{
"plugin.activity": "cn.originx.xx.extension.AspectActivity"
}
通道和插件的结构是整个Origin X
的核心结构,这部分会在下一章节说明,先看看通道中的AOP插件配置,看看一个案例:
{
"configuration.operation": "ADD",
"plugin.component.before": [
"cn.originx.uca.plugin.semi.BeforeNumber",
"cn.originx.uca.plugin.semi.BeforeLife"
],
"plugin.component": "cn.originx.scaffold.plugin.AspectBatch",
"plugin.component.after": [
"cn.originx.uca.plugin.semi.AfterEs",
"cn.originx.itsm.plugin.AfterItsm"
],
"plugin.config": {
"cn.originx.uca.plugin.semi.BeforeNumber": {
"field": "code"
}
},
"plugin.activity": "cn.originx.xx.extension.AspectActivity"
}
上述插件中,除开plugin.activity
是第二章节提到的变更历史处理插件,其他的配置就是AOP插件的核心配置。
configuration.operation
是操作类型的配置,它表示当前通道的核心操作,由于会在一些特殊场景处理操作分流的问题,所以它属于必须和当前通道绑定的options
配置,这个配置包含了三个值:
核心组件(plugin.component
)可以自己实现,也可以使用标准化的核心组件,目前标准化的核心组件如下:
插件名称 | 含义 |
---|---|
cn.originx.scaffold.plugin.AspectBatch | 批量操作插件 |
cn.originx.scaffold.plugin.AspectRecord | 单记录操作插件 |
核心组件配置在options中的plugin.component
节点中,该节点配置了核心组件的类名,如果您对AOP核心组件开发不熟悉,可以选择上述两种——不过需要分清楚当前通道处理的是单条数据还是批量数据。
节点:plugin.component.before
是一个JsonArray
的数组,它包含了当前通道要触发的所有前置插件链。节点:plugin.component.after
同样是一个JsonArray
的数组,它包含了当前通道要触发的所有后置插件链。整个通道 + 插件的执行流程如下:
cn.originx.uca.plugin.semi.BeforeNumber
插件cn.originx.uca.plugin.semi.BeforeLife
插件cn.originx.uca.plugin.semi.AfterEs
插件cn.originx.itsm.plugin.AfterItsm
插件上述所有的插件中,每个插件执行完了过后,会把处理掉的数据:JsonObject / JsonArray
直接传递给下一个插件,并且会把Options
也传递给下一个插件,形成一个完整的函数链。这些插件都实现了接口:
public interface AspectPlugin extends DataPlugin<AspectPlugin> {
@Override
default AspectPlugin bind(final DataAtom atom) {
return this;
}
@Override
default AspectPlugin bind(final DictFabric fabric) {
return this;
}
/*
* 前置函数
*/
default Future<JsonObject> beforeAsync(final JsonObject record, final JsonObject config) {
return Future.failedFuture(new _501NotSupportException(this.getClass()));
}
default Future<JsonArray> beforeAsync(final JsonArray records, final JsonObject config) {
return Future.failedFuture(new _501NotSupportException(this.getClass()));
}
/*
* 后置函数
*/
default Future<JsonObject> afterAsync(final JsonObject record, final JsonObject config) {
return Future.failedFuture(new _501NotSupportException(this.getClass()));
}
default Future<JsonArray> afterAsync(final JsonArray records, final JsonObject config) {
return Future.failedFuture(new _501NotSupportException(this.getClass()));
}
}
每个插件中都包含了绑定的DataAtom
以及当前通道需要使用的字典翻译器DictFabric
。
在整个配置中,还存在以下片段:
"plugin.config": {
"cn.originx.uca.plugin.semi.BeforeNumber": {
"field": "code"
}
}
这个片段中存储了每个配置的插件不同的配置信息,如这里可以看到的插件:cn.originx.uca.plugin.semi.BeforeNumber
的配置中会包含field = code
的配置信息,这种格式存在的限制:
I_SERVICE
的serviceConfig
来动态切换。通道中的options配置在I_SERVICE
的 serviceConfig
字段中,它的默认结构如下:
{
"name": "应用程序名称,X_APP中的NAME字段",
"sigma": "多租户场景中的统一标识 sigma",
"identifier": "模型标识符"
...
}
上述配置中,...
省略的配置就是serviceConfig
中的配置,它和默认配置合并到一起,也方便开发人员拿到合法的上下文环境。
插件中的options在前者中会有稍许的变化,如:
{
"configuration.operation": "ADD",
"name": "vie.app.ox",
"sigma": "xxx",
"identifier": "ci.server.pcs",
...
}
有几点需要说明:
identifier
和serviceConfig
中配置的identifier
可能不相等,如果使用了标识规则。器,identifier
有可能会存在变化。插件中的identifier
是变化过后的值——简单说插件的options中的identifier
是经过了标识选择器执行后的identifier
。name
和sigma
继续维持所需要的值。configuration.operation
(三个值,ADD、UPDATE、DELETE)。...
中就是plugin.config
定义的Json结构。plugin
前缀的键值配置会被自动移除掉。同一个功能,可以使用通道 / 插件两种模式实现,前提在于你所编写的接口或者任务的存在位置,这里留个引用提供给读者参考。
cn.originx.optic.advanced.CreateComponent
cn.originx.itsm.plugin.AfterItsm
{
"configuration.operation": "ADD",
"plugin.component.before": [
"cn.originx.uca.plugin.semi.BeforeNumber",
"cn.originx.uca.plugin.semi.BeforeLife"
],
"plugin.component": "cn.originx.scaffold.plugin.AspectRecord",
"plugin.component.after": [
"cn.originx.uca.plugin.semi.AfterEs",
"cn.originx.itsm.plugin.AfterItsm"
],
"plugin.config": {
"cn.originx.uca.plugin.semi.BeforeNumber": {
"field": "code"
}
},
"plugin.activity": "cn.originx.xx.extension.AspectActivity"
}
cn.originx.itsm.api.OnlineComponent
cn.originx.ucmdb.plugin.semi.BeforeUcmdb
{
"configuration.operation": "UPDATE",
"plugin.component.before": [
"cn.originx.ucmdb.plugin.semi.BeforeUcmdb",
"cn.originx.xx.extension.BeforeOwner"
],
"plugin.component": "cn.originx.scaffold.plugin.AspectBatch",
"plugin.component.after": [
"cn.originx.uca.plugin.semi.AfterEs"
],
"plugin.activity": "cn.originx.xx.extension.AspectActivity"
}
综上所述: