dubbo——spring初始化
研究dubbo就先从自己最感兴趣的开始吧
一、构建dubbo源码环境
① dubbo源码在github中,右上角fork一个分支到自己的github,然后直接git clone拉代码到本地。(用手机热点拉代码有惊喜)
② 改阿里云镜像,maven的settings.xml
<localRepository>D:/mavenRepository</localRepository> <mirrors> <mirror> <id>nexus-aliyun</id> <mirrorOf>*</mirrorOf> <name>Nexus aliyun</name> <url>http://maven.aliyun.com/nexus/content/groups/public</url> </mirror> </mirrors>
③ 导入maven项目到idea中,等待jar依赖下载。
前期学习目标:主要是过一遍源码流程,网上看的架构图都太抽象了,看完源码之后,再去理解。
二、配置解析
官方已经推荐注解形式配置dubbo的服务了,由于工作时用的都是xml配置文件配置dubbo的服务,直接从源码查找注解解析对于我来说有点无从下手的感觉。还是从xml配置文件入手顺手一点。dubbo-demo>dubbo-demo-xml>dubbo-demo-xml-provider下的一个提供xml配置例子。
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:dubbo="http://dubbo.apache.org/schema/dubbo" xmlns="http://www.springframework.org/schema/beans" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd"> <dubbo:application metadata-type="remote" name="demo-provider"/> <dubbo:metadata-report address="zookeeper://127.0.0.1:2181"/> <dubbo:registry address="zookeeper://127.0.0.1:2181"/> <dubbo:protocol name="dubbo"/> <bean id="demoService" class="org.apache.dubbo.demo.provider.DemoServiceImpl"/> <dubbo:service interface="org.apache.dubbo.demo.DemoService" ref="demoService"/> </beans>
通过spring.handlers文件找到dubbo命名空间的解析类
/* dubbo-config/dubbo-config-spring/src/main/resources/META-INF/spring.handlers */ http\://dubbo.apache.org/schema/dubbo=org.apache.dubbo.config.spring.schema.DubboNamespaceHandler http\://code.alibabatech.com/schema/dubbo=org.apache.dubbo.config.spring.schema.DubboNamespaceHandler
Apache和阿里巴巴版本的命名空间进行了统一,指向的是一个命名空间解析类
/* org.apache.dubbo.config.spring.schema.DubboNamespaceHandler#init */ public void init() { 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()); }
前面spring——scan()中是根据注解解析成BeanDefinition,还没有研究过xml解析过程,这里走一遍吧,看看什么时候会调用上面init方法
/* AbstractApplicationContex.refresh()--> AbstractApplicationContext.obtainFreshBeanFactory()--> AbstractRefreshableApplicationContext.refreshBeanFactory()--> AbstractXmlApplicationContext.loadBeanDefinitions()--> AbstractXmlApplicationContext.loadBeanDefinitions()(重载方法)--> AbstractBeanDefinitionReader.loadBeanDefinitions()--> XmlBeanDefinitionReader.loadBeanDefinitions()--> XmlBeanDefinitionReader.loadBeanDefinitions()(重载方法)--> XmlBeanDefinitionReader.doLoadBeanDefinitions()--> XmlBeanDefinitionReader.registerBeanDefinitions()--> DefaultBeanDefinitionDocumentReader.registerBeanDefinitions()--> DefaultBeanDefinitionDocumentReader.doRegisterBeanDefinitions()--> DefaultBeanDefinitionDocumentReader.parseBeanDefinitions()--> BeanDefinitionParserDelegate.parseCustomElement()--> BeanDefinitionParserDelegate.parseCustomElement()(重载方法)*/ public BeanDefinition parseCustomElement(Element ele, BeanDefinition containingBd) { //解析根节点时,获取xml根节点的xmlns属性,然后缓存起来 //dubbo的是http://dubbo.apache.org/schema/dubbo String namespaceUri = getNamespaceURI(ele); //初始化NamespaceHandler //① 获取META-INF/spring.handlers文件得到指定NamespaceHandler的className // dubbo是org.apache.dubbo.config.spring.schema.DubboNamespaceHandler //② 反射初始化并调用NamespaceHandler.init()注册所有的节点解析器 //③ 返回namespaceHandler NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri); if (handler == null) { error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", ele); return null; } //namespaceHandle根据子节点名找到解析类,解析标签生成BeanDefinition return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd)); }
DubboNamespaceHandler.parse():标签节点解析
/* org.apache.dubbo.config.spring.schema.DubboNamespaceHandler#parse */ public BeanDefinition parse(Element element, ParserContext parserContext) { //获取BeanFactory BeanDefinitionRegistry registry = parserContext.getRegistry(); //注解注解相关的解析器 registerAnnotationConfigProcessors(registry); //注册两个监听器 //DubboLifecycleComponentApplicationListener //DubboBootstrapApplicationListener(处理服务注册逻辑,IOC初始化refresh的最后一步finishrefresh()) registerApplicationListeners(registry); //标签节点解析为BeanDefinition BeanDefinition beanDefinition = super.parse(element, parserContext); setSource(beanDefinition); return beanDefinition; }
总结:springIOC初始化主要完成两个任务
1、提前初始化注解解析器,注册两个监听器,一个用于生命周期监听,一个用于serviceBean注册到注册表
2、将标签解析成bean,并生成实例
3、注册到注册表(DubboBootstrapApplicationListener.onApplicationEvent())
补充:
1、上面所有Config都继承了AbstractConfig,需要注意的是AbstractConfig的一个方法被@PostConstruct注解。
@PostConstruct注解:Bean初始化(DI)后,BeanPostProcessor处理器会以反射的方式,使bean实例执行此方法。
这里addIntoConfigManager()方法作用:将上面所有的config信息,都放入configManager中。
@PostConstruct public void addIntoConfigManager() { ApplicationModel.getConfigManager().addConfig(this); }