多场景适配、轻量级、极致灵活的扩展点框架
Flex Point 是一款面向应用的扩展点(Ext Point)框架,专为多业务场景下的"能力解耦、动态路由、灵活扩展"而设计。 他支持在不同场景下动态选择和切换业务实现,极大提升了系统的可维护性和业务创新能力。
核心特性:
- 🚀 轻量级设计 - 专注于核心扩展点功能,核心模块无Spring依赖
- 🎯 场景选择器 - 支持自定义扩展点选择器,内置CodeVersionSelector等常用选择器
- 📊 扩展点监控 - 内置扩展点调用监控、性能统计、异步处理、告警机制
- 🏷️ 元数据管理 - 灵活的扩展点标签系统,支持任意场景的元数据存储
- 🔌 开箱即用 - Spring Boot环境下零配置启动,自动扫描注册
使用场景:
- 多租户/多业务线能力隔离:不同租户/业务线可动态选择不同实现,支持灰度、A/B测试、版本切换等
- 平台型/中台型系统:平台能力通过扩展点暴露,业务方可按需接入和自定义实现
- 复杂业务处理:如订单处理、风控、营销、支付等场景下的多策略动态切换
- SaaS平台:支持多租户、多版本、多策略的灵活配置和动态切换
- 业务中台:将通用业务能力抽象为扩展点,支持各业务线按需定制
FlexPoint/
├── flexpoint-dependencies-bom/ # 依赖版本BOM管理模块,统一管理所有依赖版本
├── flexpoint-common/ # 公共模块 - 接口、注解、常量、异常等
├── flexpoint-core/ # 核心模块 - 核心功能实现,不依赖Spring
├── flexpoint-spring/ # Spring集成模块 - Spring环境下的集成
├── flexpoint-springboot/ # Spring Boot自动配置模块
├── flexpoint-test/ # 测试模块 - 测试用例和示例
└── flexpoint-examples/ # 多场景接入示例模块 - Spring Boot、Java原生
模块名 | 说明 |
---|---|
flexpoint-dependencies-bom | 依赖版本BOM管理,所有依赖版本统一配置 |
flexpoint-common | 公共基础模块,接口、注解、常量、异常等 |
flexpoint-core | 核心实现模块,扩展点注册/查找/监控 |
flexpoint-spring | Spring集成,自动扫描注册扩展点 |
flexpoint-springboot | Spring Boot自动配置,开箱即用 |
flexpoint-test | 测试模块,测试用例和示例 |
flexpoint-examples | 多场景接入示例模块(Spring Boot、Java原生) |
在项目的 pom.xml
的 dependencies 中加入以下内容:
<dependency>
<groupId>com.flexpoint</groupId>
<artifactId>flexpoint-springboot</artifactId>
<version>${revision}</version>
</dependency>
推荐业务项目通过 BOM 方式统一依赖版本:
<dependencyManagement> <dependency> <groupId>com.flexpoint</groupId> <artifactId>flexpoint-dependencies-bom</artifactId> <version>${revision}</version> <type>pom</type> <scope>import</scope> </dependency> </dependencyManagement>
在 Spring Boot 项目 pom.xml
中添加:
<dependency>
<groupId>com.flexpoint</groupId>
<artifactId>flexpoint-springboot</artifactId>
</dependency>
@FpSelector("codeVersionSelector") // 指定使用的选择器名称
public interface OrderProcessAbility extends ExtAbility {
String processOrder(String orderId, String orderData);
String getOrderStatus(String orderId);
}
import org.springframework.stereotype.Component;
@Component
public class MallOrderProcessAbility implements OrderProcessAbility {
@Override public String getCode() { return "mall-app"; }
@Override public String processOrder(String orderId, String orderData) { return "商城订单处理完成"; }
@Override public String getOrderStatus(String orderId) { return "已支付"; }
}
@Component
public class LogisticsOrderProcessAbility implements OrderProcessAbility {
@Override
public String getCode() { return "logistics"; }
@Override
public String version() { return "1.0.0"; }
@Override
public String processOrder(String orderId, String orderData) {
return "物流订单处理完成";
}
}
import org.springframework.stereotype.Component;
@Component
public class CodeVersionSelector implements Selector {
@Override
public <T extends ExtAbility> T select(List<T> candidates) {
String code = SysAppContext.getAppCode();
for (T ext : candidates) {
if (code.equals(ext.getCode())) return ext;
}
return null;
}
@Override
public String getName() { return "codeVersionSelector"; } // 与@FpSelector注解中的名称一致
}
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
@RestController
public class OrderController {
@FpExt
private OrderProcessAbility orderProcessAbility;
@GetMapping("/order/process")
public String process(String orderId, String orderData) {
return orderProcessAbility.processOrder(orderId, orderData);
}
}
// 注册扩展点
flexPoint.register(new MallOrderProcessAbilityV1());
flexPoint.register(new MallOrderProcessAbilityV2());
flexPoint.register(new LogisticsOrderProcessAbility());
// 查找扩展点(自动根据@FpSelector注解指定的选择器进行选择)
OrderProcessAbility ability = flexPoint.findAbility(OrderProcessAbility.class);
import com.flexpoint.core.selector.resolves.CodeVersionSelector;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;
@Component
public class FlexPointConfig {
/**
* 注册默认的代码版本选择器
*/
@Bean
public CodeVersionSelector codeVersionSelector() {
return new CodeVersionSelector(context -> SysAppContext.getAppCode());
}
}
- 这样,业务代码只需在请求入口(如过滤器)设置好
SysAppContext.setAppCode(appCode)
,能力查找时自动感知上下文。
import org.springframework.stereotype.Component;
@Component
public class CustomSelector implements Selector {
@Override
public <T extends ExtAbility> T select(List<T> candidates) {
String code = SysAppContext.getAppCode();
for (T ext : candidates) {
if (code.equals(ext.getCode())) return ext;
}
return null;
}
@Override
public String getName() { return "customSelector"; }
}
- 通过 @FpSelector 注解在扩展点接口上指定选择器名称:
@FpSelector("customSelector") // 指定使用名为customSelector的选择器
public interface OrderProcessAbility extends ExtAbility {
String processOrder(String orderId, String orderData);
String version();
}
// 获取扩展点调用统计
ExtMetrics metrics = flexPoint.getExtMetrics("mall:1.0.0");
System.out.println("调用次数: " + metrics.getTotalInvocations());
System.out.println("平均耗时: " + metrics.getAverageDuration() + "ms");
配置项 | 类型 | 默认值 | 说明 |
---|---|---|---|
flexpoint.enabled | boolean | true | 是否启用Flex Point框架 |
flexpoint.monitor.enabled | boolean | true | 是否启用扩展点监控功能 |
flexpoint.monitor.log-invocation | boolean | true | 是否记录扩展点调用日志 |
flexpoint.monitor.log-selection | boolean | true | 是否记录扩展点选择日志 |
flexpoint.monitor.log-exception-details | boolean | true | 是否记录异常详情 |
flexpoint.monitor.performance-stats-enabled | boolean | true | 是否启用性能统计 |
flexpoint.monitor.async-enabled | boolean | false | 是否启用异步处理 |
flexpoint.monitor.async-queue-size | int | 1000 | 异步处理队列大小 |
flexpoint.monitor.async-core-pool-size | int | 2 | 异步监控核心线程数 |
flexpoint.monitor.async-max-pool-size | int | 4 | 异步监控最大线程数 |
flexpoint.monitor.async-keep-alive-time | long | 60 | 异步监控线程保活时间(秒) |
flexpoint.registry.enabled | boolean | true | 是否启用扩展点自动注册 |
以上配置可在 application.yml 或 application.properties 中灵活配置,详细含义见上表。
- 注册扩展点时只需 flexPoint.register(ability),无需类型和元数据。
- 查找扩展点时直接 flexPoint.findAbility(AbilityClass.class),框架会根据@FpSelector注解自动查找对应的选择器。
- 自定义选择器通过 @Component 注解自动注册,或者手动调用 flexPoint.registerSelector(selector) 注册。
- 选择器的名称(getName()方法返回值)必须与@FpSelector注解中指定的名称一致。
- 推荐通过BOM统一依赖版本。
以 flexpoint-examples/spring-boot-example
为例,演示如何实现"基于上下文动态切换扩展点"的完整链路:
// src/main/java/com/flexpoint/example/springboot/framework/flexpoint/security/AppAuthFilter.java
@Component
public class AppAuthFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
String appCode = req.getHeader("X-App-Code");
SysAppContext.setAppCode(appCode);
try {
chain.doFilter(request, response);
} finally {
SysAppContext.clear();
}
}
}
// src/main/java/com/flexpoint/example/springboot/framework/flexpoint/FlexPointConfig.java
@Component
public class FlexPointConfig {
@Bean
public CodeVersionSelector codeVersionSelector() {
return new CodeVersionSelector(context -> SysAppContext.getAppCode());
}
}
// src/main/java/com/flexpoint/example/springboot/ext/OrderProcessAbility.java
@FpSelector("codeVersionSelector") // 指定使用codeVersionSelector选择器
public interface OrderProcessAbility extends ExtAbility {
String processOrder(String orderId, String orderData);
String getOrderStatus(String orderId);
}
// src/main/java/com/flexpoint/example/springboot/ext/mall/MallOrderProcessAbility.java
@Component
public class MallOrderProcessAbility implements OrderProcessAbility {
@Override public String getCode() { return "mall-app"; }
@Override public String processOrder(String orderId, String orderData) { return "商城订单处理完成"; }
@Override public String getOrderStatus(String orderId) { return "已支付"; }
}
// src/main/java/com/flexpoint/example/springboot/controller/OrderController.java
@RestController
public class OrderController {
@FpExt
private OrderProcessAbility orderProcessAbility;
@PostMapping("/api/v1/orders/process")
public String processOrder(@RequestBody Map<String, String> request) {
String orderId = request.get("orderId");
String orderData = request.get("orderData");
return orderProcessAbility.processOrder(orderId, orderData);
}
}
flexpoint:
enabled: true
monitor:
enabled: true
log-invocation: true
async-enabled: true # 启用异步监控
async-queue-size: 2000 # 队列大小
async-core-pool-size: 4 # 核心线程数
async-max-pool-size: 8 # 最大线程数
async-keep-alive-time: 120 # 线程保活时间(秒)
registry:
enabled: true
可通过注入 ExtMonitor
获取扩展点调用统计:
@Autowired
private ExtMonitor extMonitor;
ExtMetrics metrics = extMonitor.getExtMetrics(扩展点实例);
如果您觉得 Flex Point 有优化空间或有更好的设计思路,欢迎随时提交 PR(Pull Request)!我们鼓励社区共同完善和壮大本项目。
- 在 GitHub 上 fork 本项目到您的个人仓库。
- 将 fork 后的项目(即您的仓库)clone 到本地。
- 在本地新建分支进行代码修改和优化。
- commit 并 push 到您的远程仓库。
- 登录 GitHub,在您的仓库首页点击 "Pull Request" 按钮,填写说明信息后提交。
- 等待维护者 review 并合并。
欢迎任何人为 Flex Point 添砖加瓦,贡献代码。
- 注释完备:每个新增方法请按照 JavaDoc 规范标明方法说明、参数说明、返回值说明等,必要时请添加单元测试。
- 依赖规范:新增方法尽量避免引入额外的第三方库。
- 风格统一:请遵循项目现有代码风格和格式。
如有问题或需要支持,扫码加微信(备注 flex-point)
本项目采用 Apache License 2.0 许可证。
让扩展点开发更简单、更灵活!