一、服务启动(dubbo协议)
ApplicationConfig applicationConfig = new ApplicationConfig().setAppName("dubbo-server");//应用信息
//声明dubbo协议,因为sofa-rpc是支持一个接口的多协议发布
ServerConfig serverConfig = new ServerConfig()
.setProtocol("dubbo")
.setHost("127.0.0.1")
.setPort(20080)
.setSerialization("hessian2")//序列化协议
.setDaemon(false);
//发布服务,采用的是构造器模式,多次setServer就行
ProviderConfig<HelloService> providerConfig = new ProviderConfig<HelloService>()
.setInterfaceId(HelloService.class.getName())
.setBootstrap("dubbo")
.setApplication(applicationConfig)
.setRef(new HelloServiceImpl())
.setUniqueId("xxx")//UniqueId为了同一个接口能在发布为多个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);
//真正发布服务的入口,下面也是我们即将分析的代码
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对象,ProviderBootstrap对象包装了各类bootstrap的发布和取消发布
1.1 String bootstrap = providerConfig.getBootstrap();
if (StringUtils.isEmpty(bootstrap)) {//如果没设置bootstrap则使用默认的bootstrap
// Use default provider bootstrap
bootstrap = RpcConfigs.getStringValue(RpcOptions.DEFAULT_PROVIDER_BOOTSTRAP);
providerConfig.setBootstrap(bootstrap);
}
//通过SPI Extension反射获取providerBootstrap对象
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转换为dubbo 原生的ServiceConfig
2.1.1 covert(providerConfig, serviceConfig);
2.1.1.1copyApplication(providerConfig, serviceConfig);//复制应用信息
//复制服务提供者需要的注册中心信息,提供了本地缓存映射,提升复制性能
2.1.1.2DubboConvertor.copyRegistries(providerConfig, serviceConfig);
//复制ProtocolConfig协议相关的信息,包括序列化器、IO线程大小、业务线程大小、线程池、报文长度限制
2.1.1.3copyServers(providerConfig, serviceConfig);
//复制ServiceConfig相关的服务提供者信息,包括相关的接口、bean引用等,但是代码里强制set了dubbo的服务版本是1.0,如果你想用sofa-rpc去发布dubbo 2.0协议的服务,发布出来的永远是1.0的服务,因为现在sofa-rpc并没提供服务版本的概念
[issues](https://github.com/alipay/sofa-rpc/issues/587)
2.1.1.4copyProvider(providerConfig, serviceConfig);
//复制MethodConfig
2.1.1.5copyMethods(providerConfig, serviceConfig);
//通过duubo 的ServiceConfig.export方法将服务发布
2.1.2 serviceConfig.export();
//sofa-rpc还提供了默认的发布协议
2.2 DefaultProviderBootstrap
//校验参数,组装方法发布的黑白名单
2.2.1checkParameters()
// 构造请求调用器,主要是初始化服务端的Filter过滤器,包含了系统自定义的服务端的过滤器和用户自定义的过滤器
2.2.2providerProxyInvoker = new ProviderProxyInvoker(providerConfig);
//初始化过滤器链FilterChain
2.2.2.1 this.filterChain = FilterChain.buildProviderChain(providerConfig,
new ProviderInvoker(providerConfig))
//获取服务端需要加载的过滤器,providerConfig里包含了用户通过别名和Filter示例自定义的过滤器,PROVIDER_AUTO_ACTIVES是static加载的系统默认Filter过滤器,相关的过滤器我们在后续Filter过滤器原理分析
2.2.2.1.1selectActualFilters(providerConfig, PROVIDER_AUTO_ACTIVES)
//判断优先加载用户自定义的过滤器,并且只加载能加载的过滤器(这个判定在各子类定义)
2.2.2.1.2 new FilterChain(selectActualFilters(providerConfig, PROVIDER_AUTO_ACTIVES), lastFilter, providerConfig)
//根据注册中心配置获取注册中心对象
2.2.3 RegistryFactory.getRegistry(registryConfig)
//根据服务配置已经用户选择发布的服务类型初始化server对象,目前sofa-rpc仅支持三种服务端,http、sofa-bolt、rest(netty-resteasy)
2.2.4 Server server = serverConfig.buildIfAbsent();
//注册请求调用器(这里我们分析rest方式)
2.2.5 server.registerProcessor(providerConfig, providerProxyInvoker)
//初始化发布的服务bean,并将上面初始化好的ProviderProxyInvoker对象通过字节增加jdk/javassist将Invoker对象动态注入到bean里,ProviderProxyInvoker包含和服务发布后请求进入的filterchain
2.2.5.1 Object obj = ProxyFactory.buildProxy(providerConfig.getProxy(), providerConfig.getProxyClass(), instance);
//通过netty resteasy进行rest服务发布
2.2.5.2 httpServer.getDeployment().getRegistry().addResourceFactory(new SofaResourceFactory(providerConfig, obj), serverConfig.getContextPath());
//初始化SofaResteasyDeployment,展示简单的重写了ResteasyDeployment的start方法,SynchronousDispatcher里重写同步分发器的Registry
2.2.5.2.1 SynchronousDispatcher dis = new SofaSynchronousDispatcher(providerFactory)
//往资源发布工厂添加一个自定义的节点
2.2.5.2.2 SofaResourceMethodRegistry.addResourceFactory(ref, basePath)
//生成rest接口服务,这个sofa-rpc参照了jboss 的NettyJaxrsServer ,重写了其start方法,主要指支持了守护线程、支持epoll、支持线程池
2.2.6 server.start()
//监听配置文件的变化,重新加载providerConfig对象的配置属性,并重新发布rest服务
2.2.7 providerConfig.setConfigListener(new ProviderAttributeListener())
//根据发布配置,将服务发布,目前支持Consul、Service Mesh、Nacos、Zookeeper、Local、Mock方式
//注册服务,这里就是接入各类客户端的初始化和注册,不过多赘述
2.2.8 register();
2.2.8.1 registry.init();
2.2.8.2 registry.start();
2.2.8.3 registry.register(providerConfig);
三、总结
ProviderConfig:服务发布相关配置,维护了服务发布相关的基础配置信息和服务发布后的相关服务信息维护
ProviderBootstrap:服务发布的实操启动类,提供对ProviderConfig各类发布类型的export和unexport
Registry:服务发布的真正的接口,目前sofa-rpc支持ConsulRegistry、LocalRegistry、MeshRegistry(并非service mesh,只是HTTP方式)、NacosRegistry、ZookeeperRegistry、MockTestRegistry(MockTestSlowRegistry)