扩展点机制
扩展点是 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.XmlEncoderjava
// 自动加载 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=DEBUGQ: 扩展可以有依赖吗?
A: 可以,扩展也是组件,支持依赖注入。
java
@Extension
public class JsonEncoder implements MessageEncoder {
@Inject
private ObjectMapper objectMapper;
}