
这里使用的是spirng-plugin-core包,即使有多年开发经验的也不一定用过。
Plugin模式的核心架构
1. 基础接口定义规范
java
/**
* Plugin标记接口 - 泛型设计支持多种识别方式
* @param <T> 插件标识类型(枚举、字符串、类等)
*/
public interface Plugin<T> {
/**
* 判断是否支持该标识
*/
boolean supports(T type);
}
/**
* 可排序插件接口
*/
public interface OrderedPlugin<T> extends Plugin<T> {
/**
* 执行顺序,值越小优先级越高
*/
default int getOrder() {
return Ordered.LOWEST_PRECEDENCE;
}
}
2. 插件注册中心规范实现
java
/**
* 插件注册中心 - 线程安全实现
*/
@Component
public class PluginRegistry<T extends Plugin<S>, S> {
private final List<T> plugins;
private final Map<S, T> pluginCache = new ConcurrentHashMap<>();
// 构造器注入,保证不可变
public PluginRegistry(List<T> plugins) {
this.plugins = plugins != null ?
Collections.unmodifiableList(plugins) : Collections.emptyList();
}
/**
* 获取支持指定类型的插件
*/
public Optional<T> getPluginFor(S type) {
if (type == null) {
return Optional.empty();
}
// 缓存优化,避免重复查找
return Optional.ofNullable(pluginCache.computeIfAbsent(type, this::findPlugin));
}
/**
* 获取所有支持指定类型的插件(按优先级排序)
*/
public List<T> getPluginsFor(S type) {
return plugins.stream()
.filter(plugin -> plugin.supports(type))
.sorted(this::sortPlugins)
.collect(Collectors.toList());
}
private T findPlugin(S type) {
for (T plugin : plugins) {
if (plugin.supports(type)) {
return plugin;
}
}
return null;
}
private int sortPlugins(Plugin<?> p1, Plugin<?> p2) {
int order1 = p1 instanceof OrderedPlugin ? ((OrderedPlugin<?>) p1).getOrder() : 0;
int order2 = p2 instanceof OrderedPlugin ? ((OrderedPlugin<?>) p2).getOrder() : 0;
return Integer.compare(order1, order2);
}
/**
* 获取所有插件
*/
public List<T> getAllPlugins() {
return plugins;
}
}
完整的规范应用示例
1. 支付场景的规范实现
java
// 1. 定义插件标识枚举
public enum PaymentChannel {
ALIPAY("alipay", "支付宝"),
WECHAT_PAY("wechat", "微信支付"),
UNION_PAY("union", "银联支付"),
OFFLINE("offline", "线下支付");
private final String code;
private final String desc;
PaymentChannel(String code, String desc) {
this.code = code;
this.desc = desc;
}
// getter...
}
// 2. 定义插件接口
public interface PaymentPlugin extends OrderedPlugin<PaymentChannel> {
/**
* 支付操作
*/
PaymentResult pay(PaymentRequest request);
/**
* 退款操作
*/
RefundResult refund(RefundRequest request);
/**
* 查询支付状态
*/
QueryResult query(PaymentQueryRequest request);
/**
* 插件健康检查
*/
default HealthCheck healthCheck() {
return HealthCheck.healthy();
}
}
// 3. 具体插件实现
@Component
@Slf4j
public class AlipayPlugin implements PaymentPlugin {
@Override
public boolean supports(PaymentChannel channel) {
return PaymentChannel.ALIPAY == channel;
}
@Override
public int getOrder() {
return 1; // 高优先级
}
@Override
public PaymentResult pay(PaymentRequest request) {
try {
// 具体的支付宝支付逻辑
validateRequest(request);
return processAlipayPayment(request);
} catch (PaymentException e) {
log.error("支付宝支付失败: {}", request.getOrderNo(), e);
return PaymentResult.fail(e.getErrorCode(), e.getMessage());
}
}
// 其他方法实现...
}
// 4. 插件管理器
@Service
@Slf4j
public class PaymentPluginManager {
private final PluginRegistry<PaymentPlugin, PaymentChannel> pluginRegistry;
public PaymentPluginManager(List<PaymentPlugin> paymentPlugins) {
this.pluginRegistry = new PluginRegistry<>(paymentPlugins);
}
/**
* 执行支付操作
*/
public PaymentResult pay(PaymentChannel channel, PaymentRequest request) {
PaymentPlugin plugin = pluginRegistry.getPluginFor(channel)
.orElseThrow(() -> new UnsupportedPaymentChannelException("不支持的支付渠道: " + channel));
log.info("使用支付插件: {} 处理订单: {}", plugin.getClass().getSimpleName(), request.getOrderNo());
return plugin.pay(request);
}
/**
* 批量健康检查
*/
public Map<PaymentChannel, HealthCheck> healthCheck() {
Map<PaymentChannel, HealthCheck> results = new HashMap<>();
for (PaymentPlugin plugin : pluginRegistry.getAllPlugins()) {
for (PaymentChannel channel : PaymentChannel.values()) {
if (plugin.supports(channel)) {
results.put(channel, plugin.healthCheck());
}
}
}
return results;
}
}
2. 配置化的插件注册
java
/**
* 基于配置的插件注册配置
*/
@Configuration
public class PluginConfiguration {
@Bean
public PluginRegistry<PaymentPlugin, PaymentChannel> paymentPluginRegistry(
List<PaymentPlugin> paymentPlugins) {
return new PluginRegistry<>(paymentPlugins);
}
@Bean
@ConditionalOnProperty(name = "payment.alipay.enabled", havingValue = "true")
public PaymentPlugin alipayPlugin() {
return new AlipayPlugin();
}
@Bean
@ConditionalOnProperty(name = "payment.wechat.enabled", havingValue = "true")
public PaymentPlugin wechatPayPlugin() {
return new WechatPayPlugin();
}
}
高级特性实现
1. 插件生命周期管理
java
/**
* 支持生命周期的插件接口
*/
public interface LifecyclePlugin<T> extends Plugin<T> {
default void init() {
// 默认空实现
}
default void destroy() {
// 默认空实现
}
default boolean isInitialized() {
return true;
}
}
/**
* 支持生命周期的注册中心
*/
@Component
public class LifecyclePluginRegistry<T extends LifecyclePlugin<S>, S>
extends PluginRegistry<T, S> implements DisposableBean {
public LifecyclePluginRegistry(List<T> plugins) {
super(plugins);
initializePlugins();
}
private void initializePlugins() {
for (T plugin : getAllPlugins()) {
try {
plugin.init();
log.info("插件初始化成功: {}", plugin.getClass().getName());
} catch (Exception e) {
log.error("插件初始化失败: {}", plugin.getClass().getName(), e);
}
}
}
@Override
public void destroy() {
for (T plugin : getAllPlugins()) {
try {
plugin.destroy();
log.info("插件销毁成功: {}", plugin.getClass().getName());
} catch (Exception e) {
log.error("插件销毁失败: {}", plugin.getClass().getName(), e);
}
}
}
}
2. 插件链式执行
java
/**
* 支持链式执行的插件
*/
public interface ChainablePlugin<T, R> extends Plugin<T> {
R execute(R input, PluginContext context);
default boolean shouldExecute(R input, PluginContext context) {
return true;
}
}
/**
* 插件执行链
*/
public class PluginChain<T, R> {
private final List<ChainablePlugin<T, R>> plugins;
private final T type;
public PluginChain(T type, List<ChainablePlugin<T, R>> plugins) {
this.type = type;
this.plugins = plugins.stream()
.filter(plugin -> plugin.supports(type))
.collect(Collectors.toList());
}
public R execute(R input) {
R result = input;
PluginContext context = new PluginContext();
for (ChainablePlugin<T, R> plugin : plugins) {
if (plugin.shouldExecute(result, context)) {
result = plugin.execute(result, context);
}
}
return result;
}
}
最佳实践总结
1. 设计原则
-
单一职责:每个插件只负责一个明确的功能
-
开闭原则:通过新增插件扩展功能,而非修改现有代码
-
依赖倒置:依赖抽象接口,而非具体实现
2. 性能优化
java
// 使用缓存避免重复查找
private final Map<S, T> pluginCache = new ConcurrentHashMap<>();
// 懒加载优化
private final Supplier<List<T>> sortedPlugins =
Suppliers.memoize(() -> sortPlugins(plugins));
3. 错误处理
java
// 统一的异常处理
public Optional<T> getPluginSafely(S type) {
try {
return getPluginFor(type);
} catch (Exception e) {
log.error("获取插件失败: {}", type, e);
return Optional.empty();
}
}
4. 测试规范
java
@ExtendWith(MockitoExtension.class)
class PaymentPluginManagerTest {
@Mock
private PaymentPlugin alipayPlugin;
@Mock
private PaymentPlugin wechatPlugin;
private PaymentPluginManager manager;
@BeforeEach
void setUp() {
when(alipayPlugin.supports(PaymentChannel.ALIPAY)).thenReturn(true);
when(wechatPlugin.supports(PaymentChannel.WECHAT_PAY)).thenReturn(true);
manager = new PaymentPluginManager(Arrays.asList(alipayPlugin, wechatPlugin));
}
@Test
void shouldReturnCorrectPluginForChannel() {
assertThat(manager.pay(PaymentChannel.ALIPAY, request))
.isNotNull();
}
}
这样的Plugin设计模式规范应用,既保证了系统的扩展性,又确保了代码的可维护性和稳定性。
基于领域设计的实践
火车票领域设计
针对火车票不同场景进行插件式设计。
// 核心插件接口
public interface TrainChannelBusinessService extends Plugin<TrainChannel> {
TrainOrderService getOrderService();
TrainRefundService getRefundService();
TrainPaymentService getPaymentService();
TrainInvoiceService getInvoiceService();
TrainPassengerService getPassengerService();
// 获取渠道配置
ChannelConfig getChannelConfig();
}
// 订单服务接口
public interface TrainOrderService {
BaseResponse<CreateOrderOutDTO> createOrder(TrainCreateOrderDTO request);
BaseResponse<CreateOrderOutDTO> createChangeOrder(ChangeOrderRequest request);
BaseResponse<CancelOrderOutDTO> cancelOrder(CancelOrderRequest request);
}
// 退款服务接口
public interface TrainRefundService {
BaseResponse<String> refundOrder(RefundOrderRequest request);
}
// 支付服务接口
public interface TrainPaymentService {
BaseResponse<String> getPayUrl(PayUrlRequest request);
BaseResponse<String> confirmPay(ConfirmPayRequest request);
BaseResponse noticePayResult(NoticePayRequest request);
}
// 发票服务接口
public interface TrainInvoiceService {
BaseResponse<List<TrainInvoiceInfoDto>> getInvoiceList(QueryInvoiceInfoRequest request);
BaseResponse<TrainIssueRespDto> invoiceIssue(InvoiceIssueRequest request);
BaseResponse<TrainInvoiceDetailDto> queryInvoiceDetail(QueryIssueInfoRequest request);
}
// 旅客服务接口
public interface TrainPassengerService {
BaseResponse<String> addTraveler(AddTravelerRequest request);
BaseResponse<List<ApiTravelerResponse>> getConcatPassenger(ApiQueryPassengerRequest request);
BaseResponse<Boolean> deleteConcat(ApiDeleteTravelerRequest request);
}
Plugin模式的典型应用场景
1. 多渠道/多供应商集成
java
// 火车票业务 - 不同渠道实现
public class ChinaRailwayBusinessService implements TrainChannelBusinessService {
// 12306官方实现
}
public class CtripBusinessService implements TrainChannelBusinessService {
// 携程渠道实现
}
public class QunarBusinessService implements TrainChannelBusinessService {
// 去哪儿渠道实现
}
适用场景:机票、酒店、支付、短信等需要对接多个第三方服务的业务
2. 规则引擎和策略模式扩展
java
// 风控规则插件
public interface RiskControlPlugin extends Plugin<RiskScene> {
RiskResult validate(RiskRequest request);
}
// 不同风控场景
public class BlacklistPlugin implements RiskControlPlugin { /* 黑名单检查 */ }
public class FrequencyPlugin implements RiskControlPlugin { /* 频次控制 */ }
public class BehaviorPlugin implements RiskControlPlugin { /* 行为分析 */ }
3. 数据处理管道
java
// 数据清洗插件
public interface DataCleanPlugin extends Plugin<DataSourceType> {
CleanResult clean(RawData data);
}
public class HtmlEscapePlugin implements DataCleanPlugin { /* HTML转义 */ }
public class SensitiveFilterPlugin implements DataCleanPlugin { /* 敏感词过滤 */ }
public class DataFormatPlugin implements DataCleanPlugin { /* 数据格式化 */ }
4. 工作流节点扩展
java
// 审批流程插件
public interface ApprovalPlugin extends Plugin<ApprovalType> {
ApprovalResult process(ApprovalContext context);
}
public class ManagerApprovalPlugin implements ApprovalPlugin { /* 经理审批 */ }
public class FinanceApprovalPlugin implements ApprovalPlugin { /* 财务审批 */ }
public class LegalApprovalPlugin implements ApprovalPlugin { /* 法务审批 */ }
替代方案对比
| 场景 | 推荐方案 | 理由 |
|---|---|---|
| 实现数量固定(2-3个) | 策略模式 | 简单直接,维护成本低 |
| 实现会频繁增加 | Plugin模式 | 扩展性好,符合开闭原则 |
| 需要热插拔 | Plugin + SPI | 支持运行时动态加载 |
| 团队协作开发 | Plugin模式 | 解耦不同团队的代码 |
实践经验总结
从我多年的项目经验看,Plugin模式在以下情况特别有价值:
-
中台系统:需要为多个业务方提供扩展能力
-
SaaS平台:不同客户需要定制化功能
-
基础设施:如规则引擎、数据处理管道
-
开放平台:允许第三方开发者扩展功能
对于普通业务系统,如果只是简单的多分支逻辑,传统的策略模式或工厂模式通常更合适,因为:
-
代码更直观
-
调试更方便
-
性能更好
-
学习成本低
1471

被折叠的 条评论
为什么被折叠?



