首先,我们知道dubbo在以前都是基于zookeeper作为配置中心的,同时是建立在spring基础之上的。因此,就需要思考一些问题:
首先dubbo是怎样和spring集成的,也即dubbo集成在spring上需要具备什么条件?接着dubbo作为一个服务治理的微服务框架,那它的生产者和消费者与注册中心怎样进行交互的。
dubbo是基于spring的基础之上进行开发的RPC框架。需要和spring整合,必然就需要按照Spring解析默认标签和自定义标签的方式进行。而在Spring中,我们知道在Spring中是在ParseBeanDefintions(Element root,BeanDefintonParserDelegate delegate)方法对默认标签parseDefaultElement(ele,delegate)和自定义标签delegate.parseCustomElement(ele)进行了解析。可以看到对自定义标签的解析:
1.首先拿到命名空间namespaceuri
2.根据命名空间找到对应的NamespaceHandler
3.调用自定义的NamespaceHandler进行解析
而自定义标签的步骤:
1.首先创建一个需要进行扩展的组件
2.定义一个xsd文件描述组件内容
3.创建一个文件,实现BeanDefintionParser接口,用来解析xsd文件中的定义和组件定义
4.创建一个handler文件,扩展自NamespaceHandlerSupport,目的是将组件注册到spring容器
5..编写Spring.handlers和spring.schemas文件
也即我们可以通过这个找到dubbo的入口--dubbo-config-spring。
接着我们就可以找到解析schemas文件的BeanDefintionParser和NamespceHandlerSupport了。因此我们首先关注NamespaceHandkerSupport。
代码语言:javascript复制//dubbo入口
public class DubboNamespaceHandler extends NamespaceHandlerSupport implements ConfigurableSourceBeanMetadataElement {
static {
Version.checkDuplicate(DubboNamespaceHandler.class);
}
//找到入口,解析Dubbo的相关标签的
@Override
public void init() {
//将解析好的元素的key-value信息放入到BeanDefintionMap中
//registerBeanDefinitionParser(String elementName, BeanDefinitionParser parser);
//this.parsers.put(elementName, parser);
// DubboBeanDefinitionParser(Class<?> beanClass, boolean required),也是key-value的map形式
registerBeanDefinitionParser("application", new DubboBeanDefinitionParser(ApplicationConfig.class, true));
registerBeanDefinitionParser("module", new DubboBeanDefinitionParser(ModuleConfig.class, true));
registerBeanDefinitionParser("registry", new DubboBeanDefinitionParser(RegistryConfig.class, true));
registerBeanDefinitionParser("config-center", new DubboBeanDefinitionParser(ConfigCenterBean.class, true));
registerBeanDefinitionParser("metadata-report", new DubboBeanDefinitionParser(MetadataReportConfig.class, true));
registerBeanDefinitionParser("monitor", new DubboBeanDefinitionParser(MonitorConfig.class, true));
registerBeanDefinitionParser("metrics", new DubboBeanDefinitionParser(MetricsConfig.class, true));
registerBeanDefinitionParser("ssl", new DubboBeanDefinitionParser(SslConfig.class, true));
registerBeanDefinitionParser("provider", new DubboBeanDefinitionParser(ProviderConfig.class, true));
registerBeanDefinitionParser("consumer", new DubboBeanDefinitionParser(ConsumerConfig.class, true));
registerBeanDefinitionParser("protocol", new DubboBeanDefinitionParser(ProtocolConfig.class, true));
registerBeanDefinitionParser("service", new DubboBeanDefinitionParser(ServiceBean.class, true));
registerBeanDefinitionParser("reference", new DubboBeanDefinitionParser(ReferenceBean.class, false));
registerBeanDefinitionParser("annotation", new AnnotationBeanDefinitionParser());
}
/**
* 复写NamespaceHandlerSupport的parse方法,为注解配置服务
* @since 2.7.5
*/
@Override
public BeanDefinition parse(Element element, ParserContext parserContext) {
BeanDefinitionRegistry registry = parserContext.getRegistry();
//注册注解配置处理器
registerAnnotationConfigProcessors(registry);
//注册上下文监听器
registerApplicationListeners(registry);
//进行bena的解析
BeanDefinition beanDefinition = super.parse(element, parserContext);
//设置资源
setSource(beanDefinition);
return beanDefinition;
}
/**
* 将{@link ApplicationListener ApplicationListeners}注册为Spring Bean
* @since 2.7.5
*/
private void registerApplicationListeners(BeanDefinitionRegistry registry) {
//注册bean dubbo生命周期组件上下文监听
registerBeans(registry, DubboLifecycleComponentApplicationListener.class);
//注册bean dubbo服务器上下文监听
registerBeans(registry, DubboBootstrapApplicationListener.class);
}
/**
* 注册注解配置处理器
* @since 2.7.5
*/
private void registerAnnotationConfigProcessors(BeanDefinitionRegistry registry) {
AnnotationConfigUtils.registerAnnotationConfigProcessors(registry);
}
}
从入口,我们可以看到相关配置信息:
ApplicationConfig、ModuleConfig、RegistryConfig、ConfigCenterBean、MetadataReportConfig、MonitorConifg、MetricsConfig、SslConfig、ProviderConfig、ConsumerConfig、ProtocolConfig、ServiceBean、ReferenceBean,还有一个注解解析:new AnnotationBeanDefinitionParser()。这里我们需要重点关注:
ServiceBean、ReferenceBean、ConfigCenterBean、new AnnotationBeanDefintionParser()
而对于相关config的配置,我们来看一个ApplicationConfig,关注两个方法,其余带config的信息都是一些实体类的信息:
代码语言:javascript复制 //进行刷新操作,继承父类的refresh
@Override
public void refresh() {
super.refresh();
appendEnvironmentProperties();
}
//调用父类AbstractConfig#refresh方法
//进行刷新操作
public void refresh() {
//拿到环境变量信息
Environment env = ApplicationModel.getEnvironment();
try {
CompositeConfiguration compositeConfiguration = env.getPrefixedConfiguration(this);
//循环方法,将新的value设置到方法中
Method[] methods = getClass().getMethods();
for (Method method : methods) {
//setter方法
if (MethodUtils.isSetter(method)) {
try {
String value = StringUtils.trim(compositeConfiguration.getString(extractPropertyName(getClass(), method)));
//调用isTypeMatch()方法以避免重复和不正确的更新,例如,
//在ReferenceConfig中我们有两个“ setGeneric”方法。
if (StringUtils.isNotEmpty(value) && ClassUtils.isTypeMatch(method.getParameterTypes()[0], value)) {
//在具有指定参数的指定对象上,调用此方法对象表示的基础方法。
//各个参数将自动展开以匹配原始形式参数,并且必要时对原始
//参数和引用参数都进行方法调用转换。
method.invoke(this, ClassUtils.convertPrimitive(method.getParameterTypes()[0], value));
}
} catch (NoSuchMethodException e) {
logger.info("Failed to override the property " method.getName() " in "
this.getClass().getSimpleName()
", please make sure every property has getter/setter method provided.");
}
//参数sette
} else if (isParametersSetter(method)) {
String value = StringUtils.trim(compositeConfiguration.getString(extractPropertyName(getClass(), method)));
if (StringUtils.isNotEmpty(value)) {
Map<String, String> map = invokeGetParameters(getClass(), this);
map = map == null ? new HashMap<>() : map;
map.putAll(convert(StringUtils.parseParameters(value), ""));
invokeSetParameters(getClass(), this, map);
}
}
}
} catch (Exception e) {
//复写失败
logger.error("Failed to override ", e);
}
}
//添加环境变量配置信息
private void appendEnvironmentProperties() {
if (parameters == null) {
parameters = new HashMap<>();
}
//通过扩展加载器进行获取适配器
Set<InfraAdapter> adapters = ExtensionLoader.getExtensionLoader(InfraAdapter.class).getSupportedExtensionInstances();
if (CollectionUtils.isNotEmpty(adapters)) {
Map<String, String> inputParameters = new HashMap<>();
//包含信息:应用名称和hos以及扩展参数信息
inputParameters.put(APPLICATION_KEY, getName());
inputParameters.put(HOST_KEY, getHostname());
for (InfraAdapter adapter : adapters) {
//同时将SPI的扩展参数信息信息加入
Map<String, String> extraParameters = adapter.getExtraAttributes(inputParameters);
if (CollectionUtils.isNotEmptyMap(extraParameters)) {
parameters.putAll(extraParameters);
}
}
}
}
明天,我们关注ServiceBean、ReferenceBean、ConfigCenterBean、new AnnotationBeanDefintionParser()这四个!