一、自定義RPC框架使用場景示例
1. 需求場景:服務註冊與發現的自動配置
入口註解設計:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(RpcComponentRegistrar.class)
public @interface EnableRpc {
// 掃描的包路徑
String[] basePackages() default {};
// 註冊中心類型
RegistryType registry() default RegistryType.ZOOKEEPER;
// 協議類型
ProtocolType protocol() default ProtocolType.HTTP;
}
2. RpcComponentRegistrar的多階段註冊
public class RpcComponentRegistrar implements ImportBeanDefinitionRegistrar, EnvironmentAware {
private Environment environment;
@Override
public void setEnvironment(Environment environment) {
this.environment = environment;
}
@Override
public void registerBeanDefinitions(
AnnotationMetadata importingClassMetadata,
BeanDefinitionRegistry registry
) {
// 階段1:解析配置
AnnotationAttributes attributes = AnnotationAttributes.fromMap(
importingClassMetadata.getAnnotationAttributes(EnableRpc.class.getName()));
// 階段2:根據配置動態註冊核心組件
registerRegistryCenter(registry, attributes);
registerProtocolProcessor(registry, attributes);
registerLoadBalancer(registry, attributes);
// 階段3:掃描並註冊服務提供者和消費者
scanAndRegisterServices(registry, attributes);
}
private void registerRegistryCenter(
BeanDefinitionRegistry registry,
AnnotationAttributes attributes
) {
RegistryType type = attributes.getEnum("registry");
RootBeanDefinition beanDefinition = new RootBeanDefinition();
beanDefinition.setBeanClassName(getRegistryClassByType(type));
// 從Environment讀取配置(如zookeeper地址)
beanDefinition.getPropertyValues().add("address",
environment.getProperty("rpc.registry.address"));
registry.registerBeanDefinition("rpcRegistryCenter", beanDefinition);
}
private void scanAndRegisterServices(
BeanDefinitionRegistry registry,
AnnotationAttributes attributes
) {
// 1. 掃描@ServiceProvider註解的服務提供者
Set<BeanDefinition> providers = scanForAnnotations(
attributes.getStringArray("basePackages"),
ServiceProvider.class);
// 2. 為每個服務提供者註冊特殊的BeanDefinition
for (BeanDefinition providerDef : providers) {
GenericBeanDefinition enhancedDef = enhanceForProvider(providerDef);
registry.registerBeanDefinition(
providerDef.getBeanClassName(),
enhancedDef);
// 3. 同時自動註冊到服務註冊中心
registerToServiceDiscovery(providerDef);
}
// 4. 掃描@RpcReference註解的消費方
// 需要創建ReferenceBeanFactoryBean來處理動態代理
registerReferenceProcessor(registry, attributes);
}
private GenericBeanDefinition enhanceForProvider(BeanDefinition originalDef) {
GenericBeanDefinition definition = new GenericBeanDefinition(originalDef);
// 添加服務暴露的初始化邏輯
definition.setInitMethodName("exportService");
// 添加後置處理器來監聽服務狀態
definition.getPropertyValues().add("serviceRegistry",
new RuntimeBeanReference("rpcRegistryCenter"));
return definition;
}
private void registerReferenceProcessor(
BeanDefinitionRegistry registry,
AnnotationAttributes attributes
) {
// 創建處理@RpcReference註解的後置處理器
RootBeanDefinition processorDef = new RootBeanDefinition(
RpcReferenceAnnotationBeanPostProcessor.class);
// 注入必要的依賴
processorDef.getPropertyValues().add("registryCenter",
new RuntimeBeanReference("rpcRegistryCenter"));
processorDef.getPropertyValues().add("loadBalancer",
new RuntimeBeanReference("rpcLoadBalancer"));
registry.registerBeanDefinition(
"rpcReferenceAnnotationBeanPostProcessor",
processorDef);
}
}
3. RPC框架的關鍵擴展點設計
服務消費者代理工廠:
public class RpcReferenceFactoryBean implements FactoryBean<Object> {
private Class<?> interfaceType;
private String serviceName;
private LoadBalancer loadBalancer;
@Override
public Object getObject() throws Exception {
// 創建動態代理,實現RPC調用
return Proxy.newProxyInstance(
interfaceType.getClassLoader(),
new Class<?>[] {interfaceType},
new RpcInvocationHandler(serviceName, loadBalancer)
);
}
@Override
public Class<?> getObjectType() {
return interfaceType;
}
}
註解處理器:
public class RpcReferenceAnnotationBeanPostProcessor
implements BeanPostProcessor, BeanFactoryAware {
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) {
// 掃描bean中所有@RpcReference註解的字段
Field[] fields = bean.getClass().getDeclaredFields();
for (Field field : fields) {
if (field.isAnnotationPresent(RpcReference.class)) {
RpcReference reference = field.getAnnotation(RpcReference.class);
// 為每個引用創建代理並注入
Object proxy = createProxy(field.getType(), reference);
field.setAccessible(true);
try {
field.set(bean, proxy);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
}
}
return bean;
}
}
二、架構師的設計模式總結
1. 動態註冊模式
模板方法流程:
1. 解析註解元數據(AnnotationMetadata)
2. 根據元數據創建或選擇BeanDefinition
3. 修改BeanDefinition(替換BeanClass、添加構造參數)
4. 批量註冊到Registry
2. 策略模式的應用
// 根據配置動態選擇實現類
private String getRegistryClassByType(RegistryType type) {
switch (type) {
case ZOOKEEPER: return "com.rpc.registry.ZookeeperRegistry";
case NACOS: return "com.rpc.registry.NacosRegistry";
case ETCD: return "com.rpc.registry.EtcdRegistry";
default: throw new IllegalArgumentException();
}
}
3. 裝飾器模式的使用
// 增強原始BeanDefinition
private GenericBeanDefinition enhanceForProvider(BeanDefinition originalDef) {
GenericBeanDefinition definition = new GenericBeanDefinition(originalDef);
// 裝飾1:添加初始化方法
definition.setInitMethodName("exportService");
// 裝飾2:添加銷燬方法
definition.setDestroyMethodName("unexportService");
// 裝飾3:添加服務版本屬性
definition.getPropertyValues().add("version", "1.0.0");
return definition;
}
三、擴展性設計
// 允許通過SPI擴展組件
private void registerExtensions(BeanDefinitionRegistry registry) {
ServiceLoader<RpcExtension> loader = ServiceLoader.load(RpcExtension.class);
for (RpcExtension extension : loader) {
RootBeanDefinition def = new RootBeanDefinition(extension.getClass());
registry.registerBeanDefinition(
extension.extensionName(),
def
);
}
}
四、與Spring Boot AutoConfiguration的對比
| 特性 | ImportBeanDefinitionRegistrar | @Configuration + @Bean |
|---|---|---|
| 註冊時機 | 更早(在ConfigurationClassParser階段) | 稍晚(BeanFactoryPostProcessor之後) |
| 動態性 | 可根據元數據動態決定註冊哪些Bean | 靜態聲明,條件化需藉助@Conditional |
| 批量處理 | 天然支持批量掃描和註冊 | 需要手動遍歷或使用@Import多個配置 |
| Bean定義修改 | 可直接操作BeanDefinition | 只能創建新的BeanDefinition |
| 適用場景 | 框架集成、註解驅動、插件化 | 簡單條件裝配、第三方Bean聲明 |
選擇建議:
- 當需要基於註解屬性動態決定註冊邏輯時,用
ImportBeanDefinitionRegistrar - 當Bean的數量或類型在編譯期無法確定時,用
ImportBeanDefinitionRegistrar - 當只是根據條件選擇性地註冊幾個已知Bean時,用
@Configuration+@Conditional更簡單