Skip to content

扩展点机制

扩展点是 LCGYL Framework 的核心扩展机制,允许你定义可扩展的接口,让其他模块或插件提供实现。

什么是扩展点?

扩展点定义了一个契约(接口),其他组件可以提供该契约的实现。框架会自动发现和管理这些实现。

核心概念

  • 扩展点(Extension Point):定义可扩展的接口
  • 扩展(Extension):扩展点的具体实现
  • 扩展注册表(Extension Registry):管理所有扩展
  • 扩展加载器(Extension Loader):加载和实例化扩展

定义扩展点

使用 @ExtensionPoint

java
@ExtensionPoint
public interface MessageEncoder {
    
    /**
     * 编码器名称
     */
    String getName();
    
    /**
     * 是否支持指定格式
     */
    boolean supports(String format);
    
    /**
     * 编码消息
     */
    byte[] encode(Object message);
}

扩展点属性

java
@ExtensionPoint(
    id = "message-encoder",
    name = "消息编码器",
    description = "用于编码消息的扩展点",
    singleton = false,  // 是否单例
    lazy = true         // 是否延迟加载
)
public interface MessageEncoder {
    // ...
}

实现扩展

使用 @Extension

java
@Extension
public class JsonEncoder implements MessageEncoder {
    
    @Override
    public String getName() {
        return "JSON";
    }
    
    @Override
    public boolean supports(String format) {
        return "json".equalsIgnoreCase(format);
    }
    
    @Override
    public byte[] encode(Object message) {
        return JsonUtils.toJson(message).getBytes(StandardCharsets.UTF_8);
    }
}

@Extension
public class XmlEncoder implements MessageEncoder {
    
    @Override
    public String getName() {
        return "XML";
    }
    
    @Override
    public boolean supports(String format) {
        return "xml".equalsIgnoreCase(format);
    }
    
    @Override
    public byte[] encode(Object message) {
        return XmlUtils.toXml(message).getBytes(StandardCharsets.UTF_8);
    }
}

@Extension
public class ProtobufEncoder implements MessageEncoder {
    
    @Override
    public String getName() {
        return "Protobuf";
    }
    
    @Override
    public boolean supports(String format) {
        return "protobuf".equalsIgnoreCase(format);
    }
    
    @Override
    public byte[] encode(Object message) {
        return ProtobufUtils.serialize(message);
    }
}

扩展属性

java
@Extension(
    id = "json-encoder",
    name = "JSON 编码器",
    priority = 100,     // 优先级
    enabled = true      // 是否启用
)
public class JsonEncoder implements MessageEncoder {
    // ...
}

使用扩展

获取所有扩展

java
@Component
public class MessageService {
    
    @Inject
    private ExtensionRegistry extensionRegistry;
    
    public byte[] encode(Object message, String format) {
        // 获取所有编码器扩展
        List<MessageEncoder> encoders = extensionRegistry.getExtensions(MessageEncoder.class);
        
        // 找到支持的编码器
        for (MessageEncoder encoder : encoders) {
            if (encoder.supports(format)) {
                return encoder.encode(message);
            }
        }
        
        throw new UnsupportedFormatException("不支持的格式: " + format);
    }
    
    public List<String> getSupportedFormats() {
        return extensionRegistry.getExtensions(MessageEncoder.class)
            .stream()
            .map(MessageEncoder::getName)
            .collect(Collectors.toList());
    }
}

获取单个扩展

java
// 按 ID 获取
MessageEncoder encoder = extensionRegistry.getExtension(MessageEncoder.class, "json-encoder");

// 获取默认扩展(优先级最高的)
MessageEncoder defaultEncoder = extensionRegistry.getDefaultExtension(MessageEncoder.class);

// 获取可选扩展
Optional<MessageEncoder> encoder = extensionRegistry.getExtensionOptional(MessageEncoder.class, "xml-encoder");

注入扩展

java
@Component
public class MessageService {
    
    // 注入所有扩展
    @Inject
    private List<MessageEncoder> encoders;
    
    // 注入特定扩展
    @Inject
    @ExtensionId("json-encoder")
    private MessageEncoder jsonEncoder;
}

扩展优先级

设置优先级

java
@Extension(priority = 100)  // 高优先级
public class PrimaryEncoder implements MessageEncoder {
}

@Extension(priority = 50)   // 中优先级
public class SecondaryEncoder implements MessageEncoder {
}

@Extension(priority = 1)    // 低优先级(默认)
public class FallbackEncoder implements MessageEncoder {
}

优先级排序

java
// 获取按优先级排序的扩展列表
List<MessageEncoder> encoders = extensionRegistry.getExtensions(MessageEncoder.class);
// 返回顺序:PrimaryEncoder, SecondaryEncoder, FallbackEncoder

条件扩展

基于配置

java
@Extension
@ConditionalOnProperty(name = "encoder.json.enabled", havingValue = "true")
public class JsonEncoder implements MessageEncoder {
}

基于类存在

java
@Extension
@ConditionalOnClass(name = "com.google.protobuf.Message")
public class ProtobufEncoder implements MessageEncoder {
}

自定义条件

java
public class OnProductionCondition implements Condition {
    @Override
    public boolean matches(ConditionContext context) {
        return "prod".equals(context.getEnvironment().getActiveProfile());
    }
}

@Extension
@Conditional(OnProductionCondition.class)
public class ProductionEncoder implements MessageEncoder {
}

扩展生命周期

初始化回调

java
@Extension
public class JsonEncoder implements MessageEncoder, InitializingExtension {
    
    @Override
    public void afterPropertiesSet() {
        // 扩展初始化后调用
        logger.info("JsonEncoder 初始化完成");
    }
}

销毁回调

java
@Extension
public class JsonEncoder implements MessageEncoder, DisposableExtension {
    
    @Override
    public void destroy() {
        // 扩展销毁前调用
        logger.info("JsonEncoder 销毁");
    }
}

完整生命周期

java
@Extension
public class JsonEncoder implements MessageEncoder {
    
    @PostConstruct
    public void init() {
        // 初始化
    }
    
    @PreDestroy
    public void cleanup() {
        // 清理
    }
}

扩展组合

链式扩展

java
@ExtensionPoint
public interface RequestFilter {
    void filter(Request request);
}

@Extension(priority = 100)
public class AuthenticationFilter implements RequestFilter {
    @Override
    public void filter(Request request) {
        // 认证
    }
}

@Extension(priority = 90)
public class AuthorizationFilter implements RequestFilter {
    @Override
    public void filter(Request request) {
        // 授权
    }
}

@Extension(priority = 80)
public class LoggingFilter implements RequestFilter {
    @Override
    public void filter(Request request) {
        // 日志
    }
}

// 使用
@Component
public class RequestProcessor {
    
    @Inject
    private List<RequestFilter> filters;
    
    public void process(Request request) {
        // 按优先级顺序执行所有过滤器
        for (RequestFilter filter : filters) {
            filter.filter(request);
        }
    }
}

策略模式

java
@ExtensionPoint
public interface PaymentStrategy {
    String getType();
    PaymentResult pay(PaymentRequest request);
}

@Extension
public class AlipayStrategy implements PaymentStrategy {
    @Override
    public String getType() {
        return "alipay";
    }
    
    @Override
    public PaymentResult pay(PaymentRequest request) {
        // 支付宝支付
    }
}

@Extension
public class WechatPayStrategy implements PaymentStrategy {
    @Override
    public String getType() {
        return "wechat";
    }
    
    @Override
    public PaymentResult pay(PaymentRequest request) {
        // 微信支付
    }
}

// 使用
@Component
public class PaymentService {
    
    @Inject
    private List<PaymentStrategy> strategies;
    
    public PaymentResult pay(String type, PaymentRequest request) {
        return strategies.stream()
            .filter(s -> s.getType().equals(type))
            .findFirst()
            .orElseThrow(() -> new UnsupportedPaymentException(type))
            .pay(request);
    }
}

SPI 集成

使用 Java SPI

java
// META-INF/services/com.example.MessageEncoder
com.example.JsonEncoder
com.example.XmlEncoder
java
// 自动加载 SPI 扩展
@ExtensionPoint(spiEnabled = true)
public interface MessageEncoder {
}

自定义 SPI 加载

java
@Component
public class CustomExtensionLoader {
    
    public <T> List<T> loadExtensions(Class<T> type) {
        ServiceLoader<T> loader = ServiceLoader.load(type);
        List<T> extensions = new ArrayList<>();
        loader.forEach(extensions::add);
        return extensions;
    }
}

动态扩展

运行时注册

java
@Component
public class DynamicExtensionManager {
    
    @Inject
    private ExtensionRegistry extensionRegistry;
    
    public void registerEncoder(MessageEncoder encoder) {
        extensionRegistry.register(MessageEncoder.class, encoder);
    }
    
    public void unregisterEncoder(String encoderId) {
        extensionRegistry.unregister(MessageEncoder.class, encoderId);
    }
}

扩展热更新

java
@Component
public class ExtensionHotReloader {
    
    @Inject
    private ExtensionRegistry extensionRegistry;
    
    public void reload(Class<?> extensionPointType) {
        // 卸载旧扩展
        extensionRegistry.unregisterAll(extensionPointType);
        
        // 重新扫描和加载
        extensionRegistry.scan(extensionPointType);
    }
}

扩展元数据

获取扩展信息

java
@Component
public class ExtensionInfoService {
    
    @Inject
    private ExtensionRegistry extensionRegistry;
    
    public List<ExtensionInfo> getExtensionInfos(Class<?> extensionPointType) {
        return extensionRegistry.getExtensionInfos(extensionPointType);
    }
}

// ExtensionInfo 包含:
// - id: 扩展 ID
// - name: 扩展名称
// - priority: 优先级
// - enabled: 是否启用
// - className: 实现类名
// - metadata: 自定义元数据

自定义元数据

java
@Extension(
    id = "json-encoder",
    metadata = {
        @Metadata(key = "format", value = "json"),
        @Metadata(key = "version", value = "1.0")
    }
)
public class JsonEncoder implements MessageEncoder {
}

// 读取元数据
ExtensionInfo info = extensionRegistry.getExtensionInfo(MessageEncoder.class, "json-encoder");
String format = info.getMetadata("format");  // "json"

最佳实践

1. 定义清晰的扩展点接口

java
// ✅ 推荐:接口职责单一
@ExtensionPoint
public interface MessageEncoder {
    byte[] encode(Object message);
}

@ExtensionPoint
public interface MessageDecoder {
    Object decode(byte[] data);
}

// ❌ 不推荐:接口职责过多
@ExtensionPoint
public interface MessageCodec {
    byte[] encode(Object message);
    Object decode(byte[] data);
    void validate(Object message);
    void transform(Object message);
}

2. 提供默认实现

java
@Extension(priority = 0)  // 最低优先级
public class DefaultEncoder implements MessageEncoder {
    // 默认实现,当没有其他扩展时使用
}

3. 使用优先级控制顺序

java
@Extension(priority = 100)  // 明确的优先级
public class HighPriorityEncoder implements MessageEncoder {
}

4. 处理扩展不存在的情况

java
// ✅ 推荐:使用 Optional
Optional<MessageEncoder> encoder = extensionRegistry.getExtensionOptional(MessageEncoder.class, "custom");
encoder.ifPresent(e -> e.encode(message));

// 或提供默认值
MessageEncoder encoder = extensionRegistry.getExtension(MessageEncoder.class, "custom")
    .orElse(defaultEncoder);

5. 文档化扩展点

java
/**
 * 消息编码器扩展点
 * 
 * <p>用于将消息对象编码为字节数组。框架提供以下默认实现:
 * <ul>
 *   <li>JsonEncoder - JSON 格式编码</li>
 *   <li>XmlEncoder - XML 格式编码</li>
 * </ul>
 * 
 * <p>自定义实现示例:
 * <pre>
 * {@code
 * @Extension
 * public class CustomEncoder implements MessageEncoder {
 *     // ...
 * }
 * }
 * </pre>
 */
@ExtensionPoint
public interface MessageEncoder {
}

常见问题

Q: 扩展点和普通接口有什么区别?

A:

  • 扩展点由框架自动发现和管理
  • 支持优先级、条件、生命周期等特性
  • 可以动态注册和卸载

Q: 如何调试扩展加载问题?

A:

properties
logging.level.com.lcgyl.framework.core.extension=DEBUG

Q: 扩展可以有依赖吗?

A: 可以,扩展也是组件,支持依赖注入。

java
@Extension
public class JsonEncoder implements MessageEncoder {
    
    @Inject
    private ObjectMapper objectMapper;
}

下一步

Released under the Apache License 2.0