一谱邪、服務(wù)啟動(dòng)(dubbo協(xié)議)
ApplicationConfig applicationConfig = new ApplicationConfig().setAppName("dubbo-server");//應(yīng)用信息
//聲明dubbo協(xié)議,因?yàn)閟ofa-rpc是支持一個(gè)接口的多協(xié)議發(fā)布
ServerConfig serverConfig = new ServerConfig()
.setProtocol("dubbo")
.setHost("127.0.0.1")
.setPort(20080)
.setSerialization("hessian2")//序列化協(xié)議
.setDaemon(false);
//發(fā)布服務(wù)楞泼,采用的是構(gòu)造器模式驰徊,多次setServer就行
ProviderConfig<HelloService> providerConfig = new ProviderConfig<HelloService>()
.setInterfaceId(HelloService.class.getName())
.setBootstrap("dubbo")
.setApplication(applicationConfig)
.setRef(new HelloServiceImpl())
.setUniqueId("xxx")//UniqueId為了同一個(gè)接口能在發(fā)布為多個(gè)bean
.setServer(serverConfig)
.setRegister(false);
ProviderConfig<EchoService> providerConfig2 = new ProviderConfig<EchoService>()
.setInterfaceId(EchoService.class.getName())
.setRef(new EchoServiceImpl())
.setApplication(applicationConfig)
.setBootstrap("dubbo")
.setUniqueId("xxx")
.setServer(serverConfig)
.setRegister(false);
//真正發(fā)布服務(wù)的入口,下面也是我們即將分析的代碼
providerConfig.export();
providerConfig2.export();
LOGGER.warn("started at pid {}", RpcRuntimeContext.PID);
synchronized (DubboServerMain.class) {
while (true) {
try {
DubboServerMain.class.wait();
} catch (InterruptedException e) {
}
}
}
}
二堕阔、源碼分析
1.providerBootstrap = Bootstraps.from(this);//初始化ProviderBootstrap對(duì)象棍厂,ProviderBootstrap對(duì)象包裝了各類(lèi)bootstrap的發(fā)布和取消發(fā)布
1.1 String bootstrap = providerConfig.getBootstrap();
if (StringUtils.isEmpty(bootstrap)) {//如果沒(méi)設(shè)置bootstrap則使用默認(rèn)的bootstrap
// Use default provider bootstrap
bootstrap = RpcConfigs.getStringValue(RpcOptions.DEFAULT_PROVIDER_BOOTSTRAP);
providerConfig.setBootstrap(bootstrap);
}
//通過(guò)SPI Extension反射獲取providerBootstrap對(duì)象
ProviderBootstrap providerBootstrap = ExtensionLoaderFactory.getExtensionLoader(ProviderBootstrap.class)
.getExtension(bootstrap, new Class[] { ProviderConfig.class }, new Object[] { providerConfig });
2.providerBootstrap.export();//目前sofa-rpc提供了兩種bootstrap,DefaultProviderBootstrap和DubboProviderBootstrap
2.1 DubboProviderBootstrap
//將providerBootstrap轉(zhuǎn)換為dubbo 原生的ServiceConfig
2.1.1 covert(providerConfig, serviceConfig);
2.1.1.1copyApplication(providerConfig, serviceConfig);//復(fù)制應(yīng)用信息
//復(fù)制服務(wù)提供者需要的注冊(cè)中心信息超陆,提供了本地緩存映射牺弹,提升復(fù)制性能
2.1.1.2DubboConvertor.copyRegistries(providerConfig, serviceConfig);
//復(fù)制ProtocolConfig協(xié)議相關(guān)的信息,包括序列化器、IO線程大小张漂、業(yè)務(wù)線程大小晶默、線程池、報(bào)文長(zhǎng)度限制
2.1.1.3copyServers(providerConfig, serviceConfig);
//復(fù)制ServiceConfig相關(guān)的服務(wù)提供者信息航攒,包括相關(guān)的接口磺陡、bean引用等,但是代碼里強(qiáng)制set了dubbo的服務(wù)版本是1.0屎债,如果你想用sofa-rpc去發(fā)布dubbo 2.0協(xié)議的服務(wù)仅政,發(fā)布出來(lái)的永遠(yuǎn)是1.0的服務(wù),因?yàn)楝F(xiàn)在sofa-rpc并沒(méi)提供服務(wù)版本的概念
[issues](https://github.com/alipay/sofa-rpc/issues/587)
2.1.1.4copyProvider(providerConfig, serviceConfig);
//復(fù)制MethodConfig
2.1.1.5copyMethods(providerConfig, serviceConfig);
//通過(guò)duubo 的ServiceConfig.export方法將服務(wù)發(fā)布
2.1.2 serviceConfig.export();
//sofa-rpc還提供了默認(rèn)的發(fā)布協(xié)議
2.2 DefaultProviderBootstrap
//校驗(yàn)參數(shù)盆驹,組裝方法發(fā)布的黑白名單
2.2.1checkParameters()
// 構(gòu)造請(qǐng)求調(diào)用器圆丹,主要是初始化服務(wù)端的Filter過(guò)濾器,包含了系統(tǒng)自定義的服務(wù)端的過(guò)濾器和用戶(hù)自定義的過(guò)濾器
2.2.2providerProxyInvoker = new ProviderProxyInvoker(providerConfig);
//初始化過(guò)濾器鏈FilterChain
2.2.2.1 this.filterChain = FilterChain.buildProviderChain(providerConfig,
new ProviderInvoker(providerConfig))
//獲取服務(wù)端需要加載的過(guò)濾器躯喇,providerConfig里包含了用戶(hù)通過(guò)別名和Filter示例自定義的過(guò)濾器辫封,PROVIDER_AUTO_ACTIVES是static加載的系統(tǒng)默認(rèn)Filter過(guò)濾器,相關(guān)的過(guò)濾器我們?cè)诤罄m(xù)Filter過(guò)濾器原理分析
2.2.2.1.1selectActualFilters(providerConfig, PROVIDER_AUTO_ACTIVES)
//判斷優(yōu)先加載用戶(hù)自定義的過(guò)濾器廉丽,并且只加載能加載的過(guò)濾器(這個(gè)判定在各子類(lèi)定義)
2.2.2.1.2 new FilterChain(selectActualFilters(providerConfig, PROVIDER_AUTO_ACTIVES), lastFilter, providerConfig)
//根據(jù)注冊(cè)中心配置獲取注冊(cè)中心對(duì)象
2.2.3 RegistryFactory.getRegistry(registryConfig)
//根據(jù)服務(wù)配置已經(jīng)用戶(hù)選擇發(fā)布的服務(wù)類(lèi)型初始化server對(duì)象倦微,目前sofa-rpc僅支持三種服務(wù)端,http、sofa-bolt正压、rest(netty-resteasy)
2.2.4 Server server = serverConfig.buildIfAbsent();
//注冊(cè)請(qǐng)求調(diào)用器(這里我們分析rest方式)
2.2.5 server.registerProcessor(providerConfig, providerProxyInvoker)
//初始化發(fā)布的服務(wù)bean欣福,并將上面初始化好的ProviderProxyInvoker對(duì)象通過(guò)字節(jié)增加jdk/javassist將Invoker對(duì)象動(dòng)態(tài)注入到bean里,ProviderProxyInvoker包含和服務(wù)發(fā)布后請(qǐng)求進(jìn)入的filterchain
2.2.5.1 Object obj = ProxyFactory.buildProxy(providerConfig.getProxy(), providerConfig.getProxyClass(), instance);
//通過(guò)netty resteasy進(jìn)行rest服務(wù)發(fā)布
2.2.5.2 httpServer.getDeployment().getRegistry().addResourceFactory(new SofaResourceFactory(providerConfig, obj), serverConfig.getContextPath());
//初始化SofaResteasyDeployment焦履,展示簡(jiǎn)單的重寫(xiě)了ResteasyDeployment的start方法拓劝,SynchronousDispatcher里重寫(xiě)同步分發(fā)器的Registry
2.2.5.2.1 SynchronousDispatcher dis = new SofaSynchronousDispatcher(providerFactory)
//往資源發(fā)布工廠添加一個(gè)自定義的節(jié)點(diǎn)
2.2.5.2.2 SofaResourceMethodRegistry.addResourceFactory(ref, basePath)
//生成rest接口服務(wù),這個(gè)sofa-rpc參照了jboss 的NettyJaxrsServer 嘉裤,重寫(xiě)了其start方法郑临,主要指支持了守護(hù)線程、支持epoll屑宠、支持線程池
2.2.6 server.start()
//監(jiān)聽(tīng)配置文件的變化厢洞,重新加載providerConfig對(duì)象的配置屬性,并重新發(fā)布rest服務(wù)
2.2.7 providerConfig.setConfigListener(new ProviderAttributeListener())
//根據(jù)發(fā)布配置典奉,將服務(wù)發(fā)布躺翻,目前支持Consul、Service Mesh秋柄、Nacos获枝、Zookeeper、Local骇笔、Mock方式
//注冊(cè)服務(wù),這里就是接入各類(lèi)客戶(hù)端的初始化和注冊(cè),不過(guò)多贅述
2.2.8 register();
2.2.8.1 registry.init();
2.2.8.2 registry.start();
2.2.8.3 registry.register(providerConfig);
三笨触、總結(jié)
ProviderConfig:服務(wù)發(fā)布相關(guān)配置懦傍,維護(hù)了服務(wù)發(fā)布相關(guān)的基礎(chǔ)配置信息和服務(wù)發(fā)布后的相關(guān)服務(wù)信息維護(hù)
ProviderBootstrap:服務(wù)發(fā)布的實(shí)操啟動(dòng)類(lèi),提供對(duì)ProviderConfig各類(lèi)發(fā)布類(lèi)型的export和unexport
Registry:服務(wù)發(fā)布的真正的接口芦劣,目前sofa-rpc支持ConsulRegistry粗俱、LocalRegistry、MeshRegistry(并非service mesh虚吟,只是HTTP方式)寸认、NacosRegistry、ZookeeperRegistry串慰、MockTestRegistry(MockTestSlowRegistry)