Turbo支持插件扩展功能,开发者可以通过编写插件实现自定义逻辑,而无需修改主框架代码。插件使用 SPI 机制进行加载,支持在运行时动态发现和加载。
插件目前支持应用场景包括:
src/
└── main/
└── resources/
├── plugin.properties
└── META-INF/
└── services/
├── com.didiglobal.turbo.engine.plugin.ElementPlugin
├── com.didiglobal.turbo.engine.plugin.ExpressionCalculatorPlugin
└── com.didiglobal.turbo.engine.plugin.IdGeneratorPlugin
插件顶层接口: ```java public interface Plugin { // turbo插件开关配置格式建议统一为turbo.plugin.support.${pluginName} String PLUGIN_SUPPORT_PREFIX = “turbo.plugin.support.”; // turbo插件初始化文件配置格式建议统一为turbo.plugin.init_sql.${pluginName} String PLUGIN_INIT_SQL_FILE_PREFIX = “turbo.plugin.init_sql.”; /**
public interface ElementPlugin extends Plugin{
String ELEMENT_TYPE_PREFIX = "turbo.plugin.element_type.";
ElementExecutor getElementExecutor();
ElementValidator getElementValidator();
Integer getFlowElementType();
}
public interface ExpressionCalculatorPlugin extends Plugin{
ExpressionCalculator getExpressionCalculator();
}
public interface IdGeneratorPlugin extends Plugin{
IdGenerator getIdGenerator();
}
使用 Maven 构建插件项目:
mvn archetype:generate -DgroupId=com.example.plugin -DartifactId=MyPlugin
示例:
public class MyPlugin implements IdGeneratorPlugin {
@Override
public String getName() {
return "MyPluginName";
}
@Override
public Boolean support() {
return true;
}
@Override
public Boolean init() {
System.out.println("MyPlugin initialized");
return true;
}
@Override
public IdGenerator getIdGenerator() {
return new MyDefinedIdGenerator();
}
}
在 src/main/resources/plugin.properties
中定义插件必要信息,如初始化脚本文件路径等:
turbo.plugin.init_sql.ParallelGatewayElementPlugin=sql/parallelGateway.sql
在 src/main/resources/META-INF/services/
文件夹下创建扩展插件类型接口对应全路径路名文件,并指定插件实现类:
创建 src/main/resources/META-INF/services/com.didiglobal.turbo.engine.plugin.ElementPlugin
文件,并写入:
com.didiglobal.turbo.plugin.ParallelGatewayElementPlugin
主应用会在初始化时通过 SPI 机制自动发现并加载插件。确保以下条件满足:
src/main/resources/META-INF/services/
文件夹下存在对应插件类型的全路径类名文件。ServiceLoader
加载所有插件。getName
方法,检查是否存在插件名称冲突。support
方法,判断是否需要使用该插件。getFlowElementType
方法,判断该类型元素节点是否存在冲突。
init
方法,进行初始化操作。Turbo为维持DAO层的简洁,未提供直接在DAO层的扩展能力。为解决部分插件需要在原有DAO层进行扩展,Turbo提供通过Mybatis拦截器的方式进行扩展。
CustomOperationHandler
接口示例:
public class ParallelNodeInstanceHandler implements CustomOperationHandler {
private static final Logger LOGGER = LoggerFactory.getLogger(ParallelNodeInstanceHandler.class);
@Override
public void handle(SqlCommandType commandType, MappedStatement mappedStatement, Object parameterObject, Object originalResult, SqlSessionFactory sqlSessionFactory) {
SqlSession sqlSession = sqlSessionFactory.openSession();
try {
ParallelNodeInstanceMapper mapper = sqlSession.getMapper(ParallelNodeInstanceMapper.class);
switch (commandType) {
case INSERT:
handleInsert(parameterObject, mapper);
break;
case UPDATE:
handleUpdate(parameterObject, mapper);
break;
case DELETE:
handleDelete(parameterObject, mapper);
break;
case SELECT:
handleSelect(originalResult, mapper);
break;
default:
LOGGER.warn("Unhandled command type: {}", commandType);
break;
}
} catch (Exception e) {
LOGGER.error("Exception occurred during handling. CommandType={} | ParameterObject={} | OriginalResult={}",
commandType, parameterObject, originalResult, e);
} finally {
sqlSession.close();
}
}
}
示例: ```java @Configuration @ComponentScan(“com.didiglobal.turbo.plugin”) @MapperScan(“com.didiglobal.turbo.plugin.dao”) @EnableAutoConfiguration(exclude = {DruidDataSourceAutoConfigure.class}) public class ParallelPluginConfig {
@PostConstruct public void init() { CustomOperationHandlerRegistry.registerHandler(EntityPOEnum.NODE_INSTANCE, new ParallelNodeInstanceHandler()); CustomOperationHandlerRegistry.registerHandler(EntityPOEnum.NODE_INSTANCE_LOG, new ParallelNodeInstanceLogHandler()); } } ``` —
以下是我们希望插件开发者遵循的一些配置项规范
配置项 | 配置名称 | 示例 | 配置说明 |
---|---|---|---|
turbo.plugin.support.${pluginName} | 插件开关配置 | turbo.plugin.support.ParallelGatewayElementPlugin=false | 用于控制support方法的返回值,默认返回true |
turbo.plugin.init_sql.${pluginName} | 数据库初始化脚本路径 | turbo.plugin.init_sql.ParallelGatewayElementPlugin=sql/parallelGateway.sql | 用于指定初始化脚本位置,这个脚本应该是幂等的 |
turbo.plugin.element_type.${pluginName} | 元素节点类型 | turbo.plugin.element_type.ParallelGatewayElementPlugin=9 | 支持插件使用方自己去指定元素节点类型,避免多个插件使用相同的元素类型导致冲突 |