找回密码
 立即注册
首页 业界区 业界 Dubbo源码—1.服务发布的主要流程

Dubbo源码—1.服务发布的主要流程

后沛若 2025-9-28 12:22:28
大纲
1.Dubbo 2.7和3.x版本的区别
2.Dubbo服务的基本流程和启动入口
3.Dubbo服务发布的主流程
4.服务发布时执行相关组件的初始化
5.服务发布时执行的服务实例刷新操作
6.服务发布时执行的服务实例初始化操作
7.服务发布时执行的服务实例发布操作
8.执行服务实例发布操作时的主流程
9.服务发布过程中ProxyFactory生成Invoker
10.服务发布过程中Protocol组件发布Invoker
11.服务发布过程中NettyServer的构造流程
12.服务发布过程中RegistryProtocol的服务注册
13.Dubbo服务发布的完整流程总结
 
1.Dubbo 2.7和3.x版本的区别
区别一:后者引入了ModuleDeployer组件专门做服务启动时的初始化工作。将原来的注册中心拆分为三大中心:注册中心、配置中心、元数据中心。
 
区别二:后者很多地方使用了Double Check来代替前者对方法加Synchronized锁,大量采用了Double Check + Volatile + Static来实现单例模式。
 
区别三:后者引入了MigrationRuleListener、MigrationRuleHandler、MigrationInvoker,引入DynamicDirectory代替RegistryDirectory。
 
2.Dubbo服务的基本流程和启动入口
(1)Dubbo服务的基本流程
(2)Provider启动入口
(3)Consumer启动入口
 
(1)Dubbo服务的基本流程
1.webp
(2)Provider启动入口
  1. public class Application {
  2.     public static void main(String[] args) throws Exception {
  3.         //Service和ServiceConfig是什么
  4.         //Service是一个服务,每个服务可能会包含多个接口
  5.         //ServiceConfig便是针对这个服务的一些配置
  6.         //下面传入的泛型DemoServiceImpl便是服务接口的实现
  7.         ServiceConfig<DemoServiceImpl> service = new ServiceConfig<>();
  8.         //设置服务暴露出去的接口
  9.         service.setInterface(DemoService.class);
  10.         //设置暴露出去的接口的实现类
  11.         service.setRef(new DemoServiceImpl());
  12.         //服务名称,可以在服务框架里进行定位
  13.         service.setApplication(new ApplicationConfig("dubbo-demo-api-provider"));
  14.         //所有的RPC框架,必须要和注册中心配合使用,服务启动后必须向注册中心进行注册
  15.         //注册中心可以知道每个服务有几个实例,每个实例在哪台服务器上
  16.         //进行服务调用时,要先找注册中心咨询要调用的服务有几个实例,分别都在什么机器上
  17.         //下面便是设置ZooKeeper作为注册中心的地址
  18.         service.setRegistry(new RegistryConfig("zookeeper://127.0.0.1:2181"));
  19.         
  20.         //设置元数据上报的地方
  21.         //Dubbo服务实例启动后,会有自己的元数据,需要上报到一个地方进行管理,比如zookeeper
  22.         service.setMetadataReportConfig(new MetadataReportConfig("zookeeper://127.0.0.1:2181"));
  23.         //配置完毕后,调用ServiceConfig的export()方法启动网络监听程序
  24.         //当接收到调用请求时,该网络监听程序会建立网络连接进行通信
  25.         //接收按照协议封装的请求数据,该网络监听程序会执行RPC调用
  26.         //此外,ServiceConfig的export()方法还会把自己作为一个服务实例注册到zk里
  27.         service.export();
  28.         System.out.println("dubbo service started");
  29.         new CountDownLatch(1).await();
  30.     }
  31. }
复制代码
(3)Consumer启动入口
  1. public class Application {
  2.     public static void main(String[] args) throws Exception {
  3.         //Reference和ReferenceConfig是什么
  4.         //Reference是一个引用,是对Provider端的一个服务实例的引用
  5.         //ReferenceConfig这个服务实例的引用的一些配置
  6.         //通过泛型传递了这个服务实例对外暴露的接口
  7.         ReferenceConfig<DemoService> reference = new ReferenceConfig<>();
  8.         
  9.         //设置应用名称
  10.         reference.setApplication(new ApplicationConfig("dubbo-demo-api-consumer"));
  11.         //设置注册中心的地址,默认是ZooKeeper
  12.         reference.setRegistry(new RegistryConfig("zookeeper://127.0.0.1:2181"));
  13.         //设置元数据上报地址
  14.         reference.setMetadataReportConfig(new MetadataReportConfig("zookeeper://127.0.0.1:2181"));
  15.         //设置要调用的服务的接口
  16.         reference.setInterface(DemoService.class);
  17.         //直接通过ReferenceConfig的get()方法来拿到一个DemoService接口
  18.         //它是一个动态代理接口,只要被调用,便会通过底层调用Provider服务实例的对应接口
  19.         DemoService service = reference.get();
  20.         String message = service.sayHello("dubbo");
  21.         System.out.println(message);
  22.         Thread.sleep(10000000L);
  23.     }
  24. }
复制代码
 
3.Dubbo服务发布的主流程
ServiceConfig的export()方法在进行服务发布时,首先会初始化相关组件,然后刷新服务实例,接着初始化服务实例,最后发布服务实例。
  1. public class ServiceConfig<T> extends ServiceConfigBase<T> {
  2.     ...
  3.     @Override
  4.     public void export() {
  5.         if (this.exported) {
  6.             return;
  7.         }
  8.         //prepare for export
  9.         //对比Dubbo 2.6.x和2.7.x源码,Dubbo 3.0的变动还是有点大的,比如这里使用了ModuleDeployer组件
  10.         //Dubbo服务实例内部会有很多的代码组件,通过ModuleDeployer便可以避免零零散散的去调用和初始化
  11.         //1.执行相关组件的初始化
  12.         //通过获取到的ModuleDeployer来对相关组件进行初始化
  13.         //比如会对MetadataReport元数据上报组件进行构建和初始化,以及启动(建立跟zk的连接)
  14.         getScopeModel().getDeployer().start();
  15.         synchronized (this) {
  16.             if (this.exported) {
  17.                 return;
  18.             }
  19.             //2.执行服务实例的刷新操作
  20.             //也就是刷新ProviderConfig->MethodConfig->ArgumentConfig
  21.             if (!this.isRefreshed()) {
  22.                 this.refresh();
  23.             }
  24.             if (this.shouldExport()) {
  25.                 //3.执行服务实例的初始化
  26.                 //也就是会把Metadata元数据给准备好,后续可以进行元数据上报
  27.                 this.init();
  28.                 //这是Dubbo服务实例的延迟发布的特性
  29.                 //如果设置了Dubbo服务实例是延迟发布的,当调用了export()方法后,就会进入这里
  30.                 //在延迟指定的时间后,再去进行服务的发布
  31.                 if (shouldDelay()) {
  32.                     //延迟发布
  33.                     doDelayExport();
  34.                 } else {
  35.                     //立即发布
  36.                     //4.执行服务实例的发布
  37.                     //这里可以作为服务发布的直接入口
  38.                     doExport();
  39.                 }
  40.             }
  41.         }
  42.     }
  43.     ...
  44. }
复制代码
 
4.服务发布时执行相关组件的初始化
  1. public class DefaultModuleDeployer extends AbstractDeployer<ModuleModel> implements ModuleDeployer {
  2.     //已经完成发布的服务实例集合
  3.     private List<ServiceConfigBase<?>> exportedServices = new ArrayList<>();
  4.     //下面这些组件,本身都是跟model组件体系强关联的
  5.     private ModuleModel moduleModel;
  6.     //父级ApplicationDeployer组件
  7.     private ApplicationDeployer applicationDeployer;
  8.     ...
  9.     @Override
  10.     public Future start() throws IllegalStateException {
  11.         //initialize,maybe deadlock applicationDeployer lock & moduleDeployer lock
  12.         //调用DefaultApplicationDeployer的initialize()方法
  13.         applicationDeployer.initialize();
  14.         return startSync();
  15.     }
  16.     @Override
  17.     public void prepare() {
  18.         //module这个层级是application层级的下层
  19.         //application层级是framework层级的下层
  20.         applicationDeployer.initialize();
  21.         this.initialize();
  22.     }
  23.     ...
  24. }
  25. public class DefaultApplicationDeployer extends AbstractDeployer implements ApplicationDeployer {
  26.     private final DubboShutdownHook dubboShutdownHook;
  27.     ...
  28.     @Override
  29.     public void initialize() {
  30.         if (initialized) {
  31.             return;
  32.         }
  33.         //ApplicationDeployer组件,可能会被多线程并发访问
  34.         //Ensure that the initialization is completed when concurrent calls
  35.         synchronized (startLock) {
  36.             if (initialized) {
  37.                 return;
  38.             }
  39.             //注册退出时需要进行资源销毁的ShutdownHook
  40.             //register shutdown hook
  41.             registerShutdownHook();
  42.             //启动配置中心ConfigCenter
  43.             //动配置中心是专门存放配置信息的
  44.             startConfigCenter();
  45.             //加载应用配置
  46.             loadApplicationConfigs();
  47.             //初始化ModuleDeployer
  48.             initModuleDeployers();
  49.             //启动元数据中心MetadataCenter
  50.             //元数据中心是专门存放发布d的服务实例信息的
  51.             startMetadataCenter();
  52.             initialized = true;
  53.             if (logger.isInfoEnabled()) {
  54.                 logger.info(getIdentifier() + " has been initialized!");
  55.             }
  56.         }
  57.         //老的Dubbo版本只有注册中心的概念
  58.         //后来随着版本的迭代和演进,出现了配置中心、元数据中心等这些用于解耦的概念
  59.         //虽然Dubbo的服务实例信息、配置信息、元数据信息,都可以放在zk里
  60.         //但如果把一个服务实例的各种数据和信息都存储在zk里,那么这些数据和信息会严重耦合在一起
  61.         //下面从扩展性和可用性两个层面来分析,如果把各种数据都耦合放在一个zk里可能会出现的问题
  62.         //(1)扩展性
  63.         //在一个大规模的微服务系统里,服务本身可能都有上百个,服务实例可能有几百上千个,所以服务实例数据可能就很多
  64.         //但每个服务实例关联的配置数据,可能不是太多,尤其是元数据可能也不是太多
  65.         //而这里的扩展性不是指功能上的扩展,而是指数据上的扩展
  66.         //随着服务实例数据在膨胀,配置数据和元数据虽然可能也在增加,但是增加的速度可能比不上服务实例数据
  67.         //此时就需要对注册中心进行扩容或者更换一个系统去存储
  68.         //而在这个过程之中,由于所有数据耦合在一起了,牵一发而动全身,不好扩展了
  69.         //这就是多种不同类型的数据耦合在一起时会出现的痛点,也就是数据耦合导致数据扩展性差的问题
  70.         //(2)可用性
  71.         //由于注册数据、配置数据、元数据都放在一个地方比如zk
  72.         //那么一旦zk出现了故障,这三种数据就一起没了,这就是可用性问题
  73.         //因此,Dubbo3的架构设计会对不同类型的数据进行分离,形成了三种数据:注册数据、元数据、配置数据
  74.         //于是就有了三大中心:注册中心、配置中心、元数据中心,这样就可以把三种不同类型的数据,放到不同的地方去
  75.         //在扩展性方面,当服务实例数据太多时要进行扩容或者切换存储技术,此时对另外两种数据是没有直接影响的
  76.         //在可用性方面,一旦作为注册中心的zk突然挂了,此时配置中心可能是Nacos,对它来说也没有直接影响的
  77.     }
  78.     private void registerShutdownHook() {
  79.         dubboShutdownHook.register();
  80.     }
  81.     ...
  82. }
复制代码
2.png
 
6.服务发布时执行的服务实例初始化操作
  1. public class DefaultApplicationDeployer extends AbstractDeployer implements ApplicationDeployer {
  2.     ...
  3.     //启动元数据中心
  4.     private void startMetadataCenter() {
  5.         //先分析元数据中心是否需要用注册中心来做元数据中心
  6.         useRegistryAsMetadataCenterIfNecessary();
  7.         ApplicationConfig applicationConfig = getApplication();
  8.         //获取元数据类型metadataType
  9.         String metadataType = applicationConfig.getMetadataType();
  10.         //进行元数据的配置,里面包含了MetadataReport的配置
  11.         Collection<MetadataReportConfig> metadataReportConfigs = configManager.getMetadataConfigs();
  12.         if (CollectionUtils.isEmpty(metadataReportConfigs)) {
  13.             return;
  14.         }
  15.         //从applicationModel中获取一个BeanFactory
  16.         //再根据BeanFactory获取一个元数据上报组件的实例MetadataReportInstance
  17.         MetadataReportInstance metadataReportInstance = applicationModel.getBeanFactory().getBean(MetadataReportInstance.class);
  18.         List<MetadataReportConfig> validMetadataReportConfigs = new ArrayList<>(metadataReportConfigs.size());
  19.         for (MetadataReportConfig metadataReportConfig : metadataReportConfigs) {
  20.             ConfigValidationUtils.validateMetadataConfig(metadataReportConfig);
  21.             validMetadataReportConfigs.add(metadataReportConfig);
  22.         }
  23.         //对于唯一的一个MetadataReport,会在这里进行初始化
  24.         //把配置的metadataReport地址和config传递进init()方法进行初始化
  25.         metadataReportInstance.init(validMetadataReportConfigs);
  26.         if (!metadataReportInstance.inited()) {
  27.             throw new IllegalStateException(String.format("%s MetadataConfigs found, but none of them is valid.", metadataReportConfigs.size()));
  28.         }
  29.         //所以MetadataReport的启动
  30.         //其实就是根据配置去获取对应的BeanFactory,然后通过BeanFactory创建出对应的MetadataReport实例
  31.         //最后根据配置对元数据上报组件的实例MetadataReportInstance进行初始化
  32.     }
  33.     ...
  34. }
  35. public class MetadataReportInstance implements Disposable {
  36.     ...
  37.     public void init(List<MetadataReportConfig> metadataReportConfigs) {
  38.         if (!init.compareAndSet(false, true)) {
  39.             return;
  40.         }
  41.         this.metadataType = applicationModel.getApplicationConfigManager().getApplicationOrElseThrow().getMetadataType();
  42.         if (metadataType == null) {
  43.             this.metadataType = DEFAULT_METADATA_STORAGE_TYPE;
  44.         }
  45.         //在这里会通过SPI机制的adaptive自适应,生成一个代理类
  46.         //底层会通过自适应的机制,根据url里的参数去拿到对应的实现类,来调用它的方法
  47.         //如果使用zk作为元数据中心,那么拿到的应该是一个ZooKeeperMetadataReportFactory
  48.         MetadataReportFactory metadataReportFactory = applicationModel.getExtensionLoader(MetadataReportFactory.class).getAdaptiveExtension();
  49.         for (MetadataReportConfig metadataReportConfig : metadataReportConfigs) {
  50.             init(metadataReportConfig, metadataReportFactory);
  51.         }
  52.     }
  53.     private void init(MetadataReportConfig config, MetadataReportFactory metadataReportFactory) {
  54.         ...
  55.         //这种url一般来说是针对zk的url地址
  56.         MetadataReport metadataReport = metadataReportFactory.getMetadataReport(url);
  57.         if (metadataReport != null) {
  58.             metadataReports.put(relatedRegistryId, metadataReport);
  59.         }
  60.     }
  61.     ...
  62. }
  63. public abstract class AbstractMetadataReportFactory implements MetadataReportFactory {
  64.     ...
  65.     @Override
  66.     public MetadataReport getMetadataReport(URL url) {
  67.         ...
  68.         metadataReport = createMetadataReport(url);
  69.         ...
  70.     }
  71.     protected abstract MetadataReport createMetadataReport(URL url);
  72.     ...
  73. }
  74. public class ZookeeperMetadataReportFactory extends AbstractMetadataReportFactory {
  75.     ...
  76.     @Override
  77.     public MetadataReport createMetadataReport(URL url) {
  78.         return new ZookeeperMetadataReport(url, zookeeperTransporter);
  79.     }
  80.     ...
  81. }
  82. public class ZookeeperMetadataReport extends AbstractMetadataReport {
  83.     private final String root;
  84.     ZookeeperClient zkClient;
  85.     ...
  86.     public ZookeeperMetadataReport(URL url, ZookeeperTransporter zookeeperTransporter) {
  87.         super(url);
  88.         ...
  89.         zkClient = zookeeperTransporter.connect(url);
  90.     }
  91.     ...
  92. }
复制代码
3.png
 
7.服务发布时执行的服务实例发布操作
首先调用ServiceConfig的doExportUrls()方法发布服务,然后再调用其exported()方法进行服务发布后的处理,比如打印日志和回调监听器。
  1. public class ServiceConfig<T> extends ServiceConfigBase<T> {
  2.     ...
  3.     @Override
  4.     public void export() {
  5.         ...
  6.         //1.执行相关组件的初始化
  7.         //通过获取到的ModuleDeployer来对相关组件进行初始化
  8.         //比如会对MetadataReport元数据上报组件进行构建和初始化,以及启动(建立跟zk的连接)
  9.         getScopeModel().getDeployer().start();
  10.         synchronized (this) {
  11.             if (this.exported) {
  12.                 return;
  13.             }
  14.             //2.执行服务实例的刷新操作
  15.             //也就是刷新ProviderConfig->MethodConfig->ArgumentConfig
  16.             if (!this.isRefreshed()) {
  17.                 //执行AbstractConfig的refresh()方法
  18.                 this.refresh();
  19.             }
  20.             ...
  21.         }
  22.     }
  23.     ...
  24. }
  25. public abstract class AbstractConfig implements Serializable {
  26.     ...
  27.     public void refresh() {
  28.         //check and init before do refresh
  29.         //调用AbstractConfig的子类ServiceConfigBase的preProcessRefresh()方法
  30.         //初始化一个ProviderConfig,也就是Provider服务实例
  31.         preProcessRefresh();
  32.         //Model组件体系对Dubbo的运行很关键,可以认为它是SPI机制使用的入口
  33.         //而ScopeModel是Model组件体系的一个基础,ScopeModel类型是可以转换为ModuleModel、ApplicationModel
  34.         //比如像ModuleServiceRepository、ModelEnvironment、BeanFactory等很多通用的组件都可以通过ScopeModel去获取
  35.         Environment environment = getScopeModel().getModelEnvironment();//获取Environment对象
  36.         List<Map<String, String>> configurationMaps = environment.getConfigurationMaps();
  37.         //Search props starts with PREFIX in order
  38.         //接下来要获取和拼接preferredPrefix
  39.         String preferredPrefix = null;
  40.         List<String> prefixes = getPrefixes();
  41.         for (String prefix : prefixes) {
  42.             if (ConfigurationUtils.hasSubProperties(configurationMaps, prefix)) {
  43.                 preferredPrefix = prefix;
  44.                 break;
  45.             }
  46.         }
  47.         if (preferredPrefix == null) {
  48.             preferredPrefix = prefixes.get(0);
  49.         }
  50.         ...
  51.         //使用反射注入需要的方法
  52.         assignProperties(this, environment, subProperties, subPropsConfiguration);
  53.         //process extra refresh of subclass, e.g. refresh method configs
  54.         //调用AbstractInterfaceConfig的processExtraRefresh()方法
  55.         //该方法中preferredPrefix是关键,它的值可能是:dubbo.service.org.apache.dubbo.demo.DemoService
  56.         //其中dubbo.service代表dubbo服务名称的一个固定前缀,属于固定拼接的
  57.         //而中间的org.apache.dubbo.demo,则是从服务接口所在包名里截取出来的,并且最后会加上服务接口的接口名
  58.         //所以preferredPrefix会作为当前dubbo服务的全限定的名字
  59.         //而这段refresh的代码的作用,就是处理这个preferredPrefix以及其他相关的配置信息
  60.         processExtraRefresh(preferredPrefix, subPropsConfiguration);
  61.         postProcessRefresh();
  62.         refreshed.set(true);
  63.     }
  64.     protected void preProcessRefresh() {
  65.         // pre-process refresh
  66.     }
  67.     protected void processExtraRefresh(String preferredPrefix, InmemoryConfiguration subPropsConfiguration) {
  68.         // process extra refresh
  69.     }
  70.       
  71.     protected void postProcessRefresh() {
  72.         // post-process refresh
  73.         checkDefault();
  74.     }
  75.     ...
  76. }
  77. public abstract class AbstractInterfaceConfig extends AbstractMethodConfig {
  78.     private List<MethodConfig> methods;
  79.     ...
  80.     //该方法会通过反射技术,对需要发布的服务的接口方法和参数封装成MethodConfig、ArgumentConfig
  81.     @Override
  82.     protected void processExtraRefresh(String preferredPrefix, InmemoryConfiguration subPropsConfiguration) {
  83.         if (StringUtils.hasText(interfaceName)) {
  84.             //通过反射技术获取需要发布的服务的接口
  85.             Class<?> interfaceClass;
  86.             interfaceClass = ClassUtils.forName(interfaceName);
  87.             ...
  88.             //Auto create MethodConfig/ArgumentConfig according to config props
  89.             Map<String, String> configProperties = subPropsConfiguration.getProperties();
  90.             //获取需要发布的服务的接口的所有方法
  91.             Method[] methods;
  92.             methods = interfaceClass.getMethods();
  93.             //接下来对需要发布的服务的接口方法进行处理
  94.             //整理出MethodConfig对象及其对应的ArgumentConfig对象
  95.             //接口里的每个方法都要创建一个MethodConfig
  96.             //方法里的每一个参数都要创建一个ArgumentConfig
  97.             for (Method method : methods) {
  98.                 //因为服务端每次处理客户端调用时,不可能都通过反射来获取method和args的情况
  99.                 //所以在刚开始启动时就需要对接口进行解析,将所有的method和args整理到methods属性中
  100.                 if (ConfigurationUtils.hasSubProperties(configProperties, method.getName())) {
  101.                     MethodConfig methodConfig = getMethodByName(method.getName());
  102.                     //Add method config if not found
  103.                     if (methodConfig == null) {
  104.                         //需要发布的的服务的每个方法,都创建一个MethodConfig对象
  105.                         methodConfig = new MethodConfig();
  106.                         methodConfig.setName(method.getName());
  107.                         //将MethodConfig对象添加到methods属性中
  108.                         this.addMethod(methodConfig);
  109.                     }
  110.                     //Add argument config
  111.                     //dubbo.service.{interfaceName}.{methodName}.{arg-index}.xxx=xxx
  112.                     java.lang.reflect.Parameter[] arguments = method.getParameters();
  113.                     for (int i = 0; i < arguments.length; i++) {
  114.                         if (getArgumentByIndex(methodConfig, i) == null && hasArgumentConfigProps(configProperties, methodConfig.getName(), i)) {
  115.                             //方法里的每个args参数,都创建一个ArgumentConfig对象
  116.                             ArgumentConfig argumentConfig = new ArgumentConfig();
  117.                             argumentConfig.setIndex(i);
  118.                             //将ArgumentConfig对象添加到MethodConfig对象中
  119.                             methodConfig.addArgument(argumentConfig);
  120.                         }
  121.                     }
  122.                 }
  123.             }
  124.             //refresh MethodConfigs,刷新刚才解析出来的MethodConfig对象
  125.             List<MethodConfig> methodConfigs = this.getMethods();
  126.             if (methodConfigs != null && methodConfigs.size() > 0) {
  127.                 //whether ignore invalid method config
  128.                 Object ignoreInvalidMethodConfigVal = getEnvironment().getConfiguration()
  129.                     .getProperty(ConfigKeys.DUBBO_CONFIG_IGNORE_INVALID_METHOD_CONFIG, "false");
  130.                 boolean ignoreInvalidMethodConfig = Boolean.parseBoolean(ignoreInvalidMethodConfigVal.toString());
  131.                 Class<?> finalInterfaceClass = interfaceClass;
  132.                 List<MethodConfig> validMethodConfigs = methodConfigs.stream().filter(methodConfig -> {
  133.                     methodConfig.setParentPrefix(preferredPrefix);
  134.                     //关联Model组件
  135.                     methodConfig.setScopeModel(getScopeModel());
  136.                     methodConfig.refresh();
  137.                     //verify method config
  138.                     return verifyMethodConfig(methodConfig, finalInterfaceClass, ignoreInvalidMethodConfig);
  139.                 }).collect(Collectors.toList());
  140.                 this.setMethods(validMethodConfigs);
  141.             }
  142.         }
  143.     }
  144.     public void addMethod(MethodConfig methodConfig) {
  145.         if (this.methods == null) {
  146.             this.methods = new ArrayList<>();
  147.         }
  148.         this.methods.add(methodConfig);
  149.     }
  150.     ...
  151. }
复制代码
 
8.执行服务实例发布操作时的主流程
首先通过ScopeModel组件体系获取服务数据存储组件,然后将要发布的服务注册到服务数据存储组件里,接着把相关信息封装成一个服务提供者,并将该服务提供者也注册到服务数据存储组件中,然后生成注册的URL,最后根据协议和生成的注册的URL来发布服务。
4.png
  1. public class ServiceConfig<T> extends ServiceConfigBase<T> {
  2.     ...
  3.     @Override
  4.     public void export() {
  5.         ...
  6.         synchronized (this) {
  7.             ...
  8.             if (this.shouldExport()) {
  9.                 //3.执行服务实例的初始化
  10.                 //也就是会把Metadata元数据给准备好,后续可以进行元数据上报
  11.                 this.init();
  12.                 ...
  13.             }
  14.         }
  15.     }
  16.     public void init() {
  17.         //通过SPI机制获取ServiceListener扩展点的所有实现类实例
  18.         //然后添加到ServiceConfig的serviceListeners字段里
  19.         if (this.initialized.compareAndSet(false, true)) {
  20.             //load ServiceListeners from extension
  21.             ExtensionLoader<ServiceListener> extensionLoader = this.getExtensionLoader(ServiceListener.class);
  22.             this.serviceListeners.addAll(extensionLoader.getSupportedExtensionInstances());
  23.         }
  24.         //初始化ServiceMetadata,也就是服务元数据
  25.         //这需要与前面设置的MetadataCenter元数据中心配合起来看
  26.         //ServiceMetadata作为服务实例的元数据,会对服务实例做一些描述,比如版本号、实现类等
  27.         initServiceMetadata(provider);
  28.         serviceMetadata.setServiceType(getInterfaceClass());
  29.         serviceMetadata.setTarget(getRef());
  30.         serviceMetadata.generateServiceKey();
  31.     }
  32.     ...
  33. }
复制代码
 
9.服务发布过程中ProxyFactory生成Invoker
5.png
  1. public class ServiceConfig<T> extends ServiceConfigBase<T> {
  2.     ...
  3.     @Override
  4.     public void export() {
  5.         ...
  6.         //4.执行服务实例的发布
  7.         //进行debug时,可以通过控制台打印的日志去分析运行流程
  8.         //比如通过log日志可以发现服务发布的流程可能涉及:
  9.         //一.export Dubbo Service,发布dubbo服务实例
  10.         //二.register Dubbo Service,往zk进行注册
  11.         //三.启动NettyServer,监听端口和请求处理
  12.         //四.服务发现注册
  13.         //五.MetadataReport:服务实例上报
  14.         //六.关闭JVM时的逆向处理过程
  15.         //这里可以作为一个服务发布的直接入口
  16.         doExport();
  17.     }
  18.     protected synchronized void doExport() {
  19.         ...
  20.         //发布服务
  21.         doExportUrls();
  22.         //服务发布完成后的处理,比如打印日志和回调监听器
  23.         exported();
  24.     }
  25.     ...
  26. }
复制代码
 
10.服务发布过程中Protocol组件发布Invoker
(1)Protocol协议接口
(2)Protocol组件发布Invoker
 
(1)Protocol协议接口
  1. public class ServiceConfig<T> extends ServiceConfigBase<T> {
  2.     ...  
  3.     @SuppressWarnings({"unchecked", "rawtypes"})
  4.     private void doExportUrls() {
  5.         //所谓的ScopeModel,真实的类型是ModuleModel
  6.         //下面这行代码会通过AbstractMethodConfig的getScopeModel()方法获取ScopeModel
  7.         //接着会通过ModuleModel的getServiceRepository()方法去获取ServiceRepository
  8.         //事实上,Dubbo会把它的各个组件都集中在ScopeModel(ModuleModel)里,而ScopeModel就类似于设计模式里的门面模式
  9.         //ScopeModel、ModuleModel、ApplicationModel、FrameworkModel等多个Model会组成一个Model组件体系
  10.         //1.通过ScopeModel组件体系获取服务数据存储组件ModuleServiceRepository
  11.         ModuleServiceRepository repository = getScopeModel().getServiceRepository();
  12.         //ServiceRepository是Dubbo服务的数据存储组件
  13.         //一个系统可以发布多个Dubbo服务
  14.         //每个Dubbo服务的核心就是一个接口和一个实现类
  15.         //2.把当前要发布的服务注册到Dubbo的服务数据存储组件中
  16.         ServiceDescriptor serviceDescriptor;
  17.         final boolean serverService = ref instanceof ServerService;
  18.         if (serverService) {
  19.             serviceDescriptor = ((ServerService) ref).getServiceDescriptor();
  20.             repository.registerService(serviceDescriptor);
  21.         } else {
  22.             serviceDescriptor = repository.registerService(getInterfaceClass());
  23.         }
  24.         //ProviderModel也就是服务提供者,由于这里是暴露服务出去的,所以属于Provider
  25.         //3.把所有相关的信息封装成一个服务提供者ProviderModel
  26.         providerModel = new ProviderModel(
  27.             serviceMetadata.getServiceKey(),
  28.             ref,//ref代表的是实际实现的类,通过泛型传入
  29.             serviceDescriptor,//表示服务实例相关的信息
  30.             getScopeModel(),
  31.             serviceMetadata,
  32.             interfaceClassLoader
  33.         );
  34.         providerModel.setConfig(this);
  35.         providerModel.setDestroyRunner(getDestroyRunner());
  36.         //3.将服务提供者ProviderModel注册到服务数据存储组件中
  37.         repository.registerProvider(providerModel);
  38.         //4.生成注册的URL:包含2181的端口号、注册到zk中        
  39.         //service-discovery-registry://127.0.0.1:2181/org.apache.dubbo.registry.RegistryService?application=dubbo-demo-api-provider&dubbo=2.0.2&pid=989®istry=zookeeper×tamp=1724302222103        //registry://127.0.0.1:2181/org.apache.dubbo.registry.RegistryService?application=dubbo-demo-api-provider&dubbo=2.0.2&pid=989®istry=zookeeper×tamp=1724302222103
  40.         List<URL> registryURLs = ConfigValidationUtils.loadRegistries(this, true);
  41.         for (ProtocolConfig protocolConfig : protocols) {
  42.             String pathKey = URL.buildKey(
  43.                 getContextPath(protocolConfig).map(p -> p + "/" + path).orElse(path),
  44.                 group,
  45.                 version
  46.             );
  47.             //stub service will use generated service name
  48.             if (!serverService) {
  49.                 //In case user specified path, register service one more time to map it to path.
  50.                 //将接口注册到服务数据存储组件中
  51.                 repository.registerService(pathKey, interfaceClass);
  52.             }
  53.             //5.调用doExportUrlsFor1Protocol()方法,根据协议和注册的URL来发布服务
  54.             doExportUrlsFor1Protocol(protocolConfig, registryURLs);
  55.         }
  56.         providerModel.setServiceUrls(urls);
  57.     }
  58.     private void doExportUrlsFor1Protocol(ProtocolConfig protocolConfig, List<URL> registryURLs) {
  59.         Map<String, String> map = buildAttributes(protocolConfig);
  60.         //remove null key and null value
  61.         map.keySet().removeIf(key -> StringUtils.isEmpty(key) || StringUtils.isEmpty(map.get(key)));
  62.         //init serviceMetadata attachments
  63.         //将map数据放入serviceMetadata中,这与元数据相关
  64.         serviceMetadata.getAttachments().putAll(map);
  65.         //根据ProtocolConfig构建URL
  66.         URL url = buildUrl(protocolConfig, map);
  67.         //发布服务
  68.         exportUrl(url, registryURLs);
  69.     }
  70.     ...
  71. }
  72. //ScopeModel、ModuleModel、ApplicationModel、FrameworkModel等多个Model会组成一个Model组件体系
  73. public class ModuleModel extends ScopeModel {
  74.     public static final String NAME = "ModuleModel";
  75.     //ApplicationModel内部封装了其他很多组件,在这里是一个引用关系,通过构造方法传入进来
  76.     private final ApplicationModel applicationModel;
  77.     //包含了ServiceModule环境相关的数据,里面封装的都是各种各样的配置信息
  78.     private ModuleEnvironment moduleEnvironment;
  79.     //serviceRepository是一个服务仓储组件,存储了一些服务相关的数据
  80.     private ModuleServiceRepository serviceRepository;
  81.     //这是module配置管理器,用于存放一些服务相关的配置数据
  82.     private ModuleConfigManager moduleConfigManager;
  83.     //这是ModuleDeployer组件,用于管理其他的一些组件和模块的生命周期
  84.     private ModuleDeployer deployer;
  85.     ...
  86. }
  87. public class ApplicationModel extends ScopeModel {
  88.     ...
  89.     //包含了多个ModuleModel
  90.     private final List<ModuleModel> moduleModels = new CopyOnWriteArrayList<>();
  91.     private final List<ModuleModel> pubModuleModels = new CopyOnWriteArrayList<>();
  92.     //环境变量、配置信息
  93.     private Environment environment;
  94.     //服务配置相关的一些信息
  95.     private ConfigManager configManager;
  96.     //服务数据相关的一些存储
  97.     private ServiceRepository serviceRepository;
  98.     //属于application层级的一些组件的生命周期管理
  99.     private ApplicationDeployer deployer;
  100.     //父级组件
  101.     private final FrameworkModel frameworkModel;
  102.     //内部的一个ModuleModel组件
  103.     private ModuleModel internalModule;
  104.     //默认的一个ModuleModel组件
  105.     private volatile ModuleModel defaultModule;
  106.     //internal module index is 0, default module index is 1
  107.     private AtomicInteger moduleIndex = new AtomicInteger(0);
  108.     //是一个锁
  109.     private Object moduleLock = new Object();
  110.     ...
  111. }
  112. public class FrameworkModel extends ScopeModel {
  113.     ...
  114.     //它没有父层级了,所以只能通过static静态变量,类级别去引用自己的FrameworkModel集合
  115.     private static List<FrameworkModel> allInstances = new CopyOnWriteArrayList<>();
  116.     //包含了多个ApplicationModel
  117.     private List applicationModels = new CopyOnWriteArrayList<>();
  118.     //通过Framework、Application、Module各个层级都可以获取到service相关的配置和数据
  119.     private FrameworkServiceRepository serviceRepository;
  120.     ...
  121. }
  122. public class ModuleServiceRepository {
  123.     private final ModuleModel moduleModel;
  124.     //services,代表服务相关的数据,StubServiceDescriptor
  125.     private final ConcurrentMap<String, List<ServiceDescriptor>> services = new ConcurrentHashMap<>();
  126.     //consumers(key - group/interface:version, value - consumerModel list)
  127.     //代表服务的调用方(consumer即消费方/调用方)
  128.     private final ConcurrentMap<String, List<ConsumerModel>> consumers = new ConcurrentHashMap<>();
  129.     //providers,代表服务提供方
  130.     private final ConcurrentMap<String, ProviderModel> providers = new ConcurrentHashMap<>();
  131.     //FrameworkServiceRepository存储的也是一些服务相关的数据
  132.     private final FrameworkServiceRepository frameworkServiceRepository;
  133.     ...
  134. }
  135. public class ModuleServiceRepository {
  136.     //services,代表服务相关的数据,StubServiceDescriptor
  137.     private final ConcurrentMap<String, List<ServiceDescriptor>> services = new ConcurrentHashMap<>();
  138.     ...
  139.     public ServiceDescriptor registerService(ServiceDescriptor serviceDescriptor) {
  140.         return registerService(serviceDescriptor.getServiceInterfaceClass(), serviceDescriptor);
  141.     }
  142.     public ServiceDescriptor registerService(Class<?> interfaceClazz) {
  143.         ServiceDescriptor serviceDescriptor = new ReflectionServiceDescriptor(interfaceClazz);
  144.         return registerService(interfaceClazz, serviceDescriptor);
  145.     }
  146.     public ServiceDescriptor registerService(Class<?> interfaceClazz, ServiceDescriptor serviceDescriptor) {
  147.         List<ServiceDescriptor> serviceDescriptors = services.computeIfAbsent(interfaceClazz.getName(), k -> new CopyOnWriteArrayList<>());
  148.         synchronized (serviceDescriptors) {
  149.             Optional<ServiceDescriptor> previous = serviceDescriptors.stream()
  150.                 .filter(s -> s.getServiceInterfaceClass().equals(interfaceClazz)).findFirst();
  151.             if (previous.isPresent()) {
  152.                 return previous.get();
  153.             } else {
  154.                 serviceDescriptors.add(serviceDescriptor);
  155.                 return serviceDescriptor;
  156.             }
  157.         }
  158.     }
  159.     ...
  160. }
复制代码
6.png
(2)Protocol组件发布Invoker
本地发布时使用InjvmProtocol + InjvmExporter,远程发布时使用RegistryProtocol + DestroyableExporter。
 
RegistryProtocol的export()方法被远程发布调用的时候,会调用到DubboProtocol的export()方法,并最终调用到HeaderExchanger的bind()方法执行NettyTransporter的bind()方法构建Netty服务器。
7.png
  1. public class ServiceConfig<T> extends ServiceConfigBase<T> {
  2.     ...
  3.     private void doExportUrlsFor1Protocol(ProtocolConfig protocolConfig, List<URL> registryURLs) {
  4.         Map<String, String> map = buildAttributes(protocolConfig);
  5.         //remove null key and null value
  6.         map.keySet().removeIf(key -> StringUtils.isEmpty(key) || StringUtils.isEmpty(map.get(key)));
  7.         //init serviceMetadata attachments
  8.         //将map数据放入serviceMetadata中,这与元数据相关
  9.         serviceMetadata.getAttachments().putAll(map);
  10.         //根据ProtocolConfig构建URL
  11.         URL url = buildUrl(protocolConfig, map);
  12.         //发布服务
  13.         exportUrl(url, registryURLs);
  14.     }
  15.     private URL buildUrl(ProtocolConfig protocolConfig, Map<String, String> params) {
  16.         //获取协议名称
  17.         String name = protocolConfig.getName();
  18.         if (StringUtils.isEmpty(name)) {
  19.             //默认使用Dubbo协议
  20.             name = DUBBO;
  21.         }
  22.         //获取host值
  23.         String host = findConfiguredHosts(protocolConfig, provider, params);
  24.         //获取port值
  25.         Integer port = findConfiguredPort(protocolConfig, provider, this.getExtensionLoader(Protocol.class), name, params);
  26.         //根据上面获取的host、port以及前文获取的map集合组装URL
  27.         URL url = new ServiceConfigURL(name, null, null, host, port, getContextPath(protocolConfig).map(p -> p + "/" + path).orElse(path), params);
  28.         //通过Configurator覆盖或添加新的参数
  29.         if (this.getExtensionLoader(ConfiguratorFactory.class).hasExtension(url.getProtocol())) {
  30.             url = this.getExtensionLoader(ConfiguratorFactory.class).getExtension(url.getProtocol()).getConfigurator(url).configure(url);
  31.         }
  32.         url = url.setScopeModel(getScopeModel());
  33.         url = url.setServiceModel(providerModel);
  34.         return url;
  35.     }
  36.     private void exportUrl(URL url, List<URL> registryURLs) {
  37.         //从URL中获取scope参数,其中可选值有none、remote、local三个,分别代表不发布、发布到本地以及发布到远端
  38.         String scope = url.getParameter(SCOPE_KEY);
  39.         //scope不为none,才进行发布
  40.         if (!SCOPE_NONE.equalsIgnoreCase(scope)) {
  41.             //scope为local,只发布到本地
  42.             if (!SCOPE_REMOTE.equalsIgnoreCase(scope)) {
  43.                 exportLocal(url);
  44.             }
  45.             //export to remote if the config is not local (export to local only when config is local)
  46.             //scope为remote,发布到远端的注册中心
  47.             if (!SCOPE_LOCAL.equalsIgnoreCase(scope)) {
  48.                 //进行远程发布
  49.                 url = exportRemote(url, registryURLs);
  50.                 if (!isGeneric(generic) && !getScopeModel().isInternal()) {
  51.                     //通过MetadataUtils推送这个服务实例的元数据到元数据中心
  52.                     //元数据中心是一个动态的配置中心,可以从里面获取参数,也可以添加监听器监听配置项的变更
  53.                     MetadataUtils.publishServiceDefinition(url, providerModel.getServiceModel(), getApplicationModel());
  54.                 }
  55.             }
  56.         }
  57.         this.urls.add(url);
  58.     }
  59.     private void exportLocal(URL url) {
  60.         //创建新URL
  61.         URL local = URLBuilder.from(url)
  62.             .setProtocol(LOCAL_PROTOCOL)
  63.             .setHost(LOCALHOST_VALUE)
  64.             .setPort(0)
  65.             .build();
  66.         local = local.setScopeModel(getScopeModel()).setServiceModel(providerModel);
  67.         //本地发布
  68.         doExportUrl(local, false);
  69.         //exportLocal,指的是发布到本地
  70.         //具体就是在jvm内部完成了组件之间的一些交互关系和发布
  71.         logger.info("Export dubbo service " + interfaceClass.getName() + " to local registry url : " + local);
  72.     }
  73.     private URL exportRemote(URL url, List<URL> registryURLs) {
  74.         //如果当前配置了至少一个注册中心
  75.         if (CollectionUtils.isNotEmpty(registryURLs)) {
  76.             //URL里有很多的信息,比如协议、各种参数等
  77.             //URL可以在后续代码运行过程中提供配置和信息
  78.             //接下来会向每个注册中心发布服务
  79.             for (URL registryURL : registryURLs) {
  80.                 //registryURL.getProtocol()会获取协议
  81.                 if (SERVICE_REGISTRY_PROTOCOL.equals(registryURL.getProtocol())) {
  82.                     url = url.addParameterIfAbsent(SERVICE_NAME_MAPPING_KEY, "true");
  83.                 }
  84.                 //injvm协议只在exportLocal()中有用,不会将服务发布到注册中心,所以这里忽略injvm协议
  85.                 if (LOCAL_PROTOCOL.equalsIgnoreCase(url.getProtocol())) {
  86.                     continue;
  87.                 }
  88.                 //设置服务URL的dynamic参数
  89.                 url = url.addParameterIfAbsent(DYNAMIC_KEY, registryURL.getParameter(DYNAMIC_KEY));
  90.                 //创建monitorUrl,并作为monitor参数添加到服务URL中
  91.                 URL monitorUrl = ConfigValidationUtils.loadMonitor(this, registryURL);
  92.                 if (monitorUrl != null) {
  93.                     url = url.putAttribute(MONITOR_KEY, monitorUrl);
  94.                 }
  95.                 //For providers, this is used to enable custom proxy to generate invoker
  96.                 //设置服务URL的proxy参数,即生成动态代理方式(jdk或是javassist),作为参数添加到RegistryURL中
  97.                 String proxy = url.getParameter(PROXY_KEY);
  98.                 if (StringUtils.isNotEmpty(proxy)) {
  99.                     registryURL = registryURL.addParameter(PROXY_KEY, proxy);
  100.                 }
  101.                 doExportUrl(registryURL.putAttribute(EXPORT_KEY, url), true);
  102.             }
  103.         } else {
  104.             //不存在注册中心,仅发布服务,不会将服务信息发布到注册中心
  105.             doExportUrl(url, true);
  106.         }
  107.         return url;
  108.     }
  109.     private void doExportUrl(URL url, boolean withMetaData) {
  110.         //动态代理技术有很多种,比如cglib,jdk
  111.         //而动态代理就是:面向一个接口,动态生成该接口的一个实现类,然后根据这个实现类再动态生成对应的对象
  112.         //这个对象就是动态代理的对象,所以该对象会代理自己背后的一个实现类
  113.         //当这个对象被调用时,背后的实现类也会被调用
  114.         //ProxyFactory,Proxy就是动态代理
  115.         //下面传入的ref指的是实现类
  116.         //下面传入的interfaceClass指的是接口
  117.         //下面传入的url就是服务实例对外暴露出去的一些核心信息
  118.         //proxyFactory.getInvoker()获取到的是Invoker调用组件
  119.         //当Dubbo的NettyServer监听到网络连接进行请求处理时,需要有一个调用组件去根据请求进行调用
  120.         //Invoker调用组件可以认为是ProxyFactory基于DemoService接口生成的动态代理
  121.         //当需要根据请求调用接口时,底层就会回调自己写的实现类DemoServiceImpl
  122.         //proxyFactory.getInvoker()会封装一个AbstractProxyInvoker,对本地实现类进行代理
  123.         //默认情况下,会通过Javassist技术生成Wrapper,该Wrapper会将本地实现类包装进去
  124.         //调用AbstractProxyInvoker的invoke方法时,最终就会基于Javassist动态生成的Wrapper进行调用
  125.         //下面这一行代码是为服务实现类的对象创建相应的Invoker
  126.         //其中传入的服务url会作为export参数添加到RegistryURL中
  127.         //这里的proxyFactory就是ProxyFactory接口的适配器,会通过SPI机制进行初始化
  128.         //比如下面就会调用JavassistProxyFactory.getInvoker()方法
  129.         //proxyFactory.getInvoker()会获取到Invoker调用组件(生成Invoker动态代理)
  130.         //所以下面这一行代码会为本地实现类的对象创建相应的Invoker(封装着AbstractProxyInvoker)
  131.         Invoker<?> invoker = proxyFactory.getInvoker(ref, (Class) interfaceClass, url);
  132.         if (withMetaData) {
  133.             //DelegateProviderMetaDataInvoker是个装饰类
  134.             //它会将当前ServiceConfig和Invoker关联起来
  135.             invoker = new DelegateProviderMetaDataInvoker(invoker, this);
  136.         }
  137.         //调用Protocol的实现进行发布,protocolSPI是Protocol接口的适配器
  138.         //进行本地发布时,使用的是InjvmProtocol + InjvmExporter
  139.         //进行远程发布时,使用的是RegistryProtocol,它会对DubboProtocol进行包装和装饰
  140.         //RegistryProtocol会先执行来处理服务注册的一些事情
  141.         //DubboProtocol会后执行来启动NettyServer网络服务器
  142.         Exporter<?> exporter = protocolSPI.export(invoker);
  143.         exporters.add(exporter);
  144.     }
  145.     ...
  146. }
  147. public class JavassistProxyFactory extends AbstractProxyFactory {
  148.     ...
  149.     @Override
  150.     public <T> Invoker<T> getInvoker(T proxy, Class<T> type, URL url) throws RpcException {
  151.         //下面会通过Wrapper创建一个包装类对象
  152.         //该对象是动态构建出来的,它属于Wrapper的一个子类,里面会拼接一个关键的方法invokeMethod(),拼接代码由javassist动态生成
  153.         final Wrapper wrapper = Wrapper.getWrapper(proxy.getClass().getName().indexOf('$') < 0 ? proxy.getClass() : type);
  154.         //下面会创建一个实现了AbstractProxyInvoker的匿名内部类
  155.         //其doInvoker()方法会直接委托给Wrapper对象的invokeMethod()方法
  156.         return new AbstractProxyInvoker<T>(proxy, type, url) {
  157.             @Override
  158.             protected Object doInvoke(T proxy, String methodName, Class<?>[] parameterTypes, Object[] arguments) throws Throwable {
  159.                 //当AbstractProxyInvoker.invoke()方法被调用时,便会执行到这里
  160.                 //这里会通过类似于JDK反射的技术,调用本地实现类如DemoServiceImpl.sayHello()
  161.                 //这个wrapper对象是由javassist技术动态生成的,已经对本地实现类进行包装
  162.                 //这个动态生成的wrapper对象会通过javassist技术自己特有的方法
  163.                 //在invokerMethod()方法被调用时执行本地实现类的目标方法
  164.                 return wrapper.invokeMethod(proxy, methodName, parameterTypes, arguments);
  165.             }
  166.         };
  167.     }
  168.     ...
  169. }
  170. public abstract class AbstractProxyInvoker<T> implements Invoker<T> {
  171.     ...
  172.     //当Netty Server接受到了请求后,经过解析就会知道是要调用什么
  173.     //然后会把解析出来的数据放入Invocation中,通过AbstractProxyInvoker的invoke()方法来进行调用
  174.     @Override
  175.     public Result invoke(Invocation invocation) throws RpcException {
  176.         ...
  177.         //执行doInvoke()方法,调用业务实现
  178.         Object value = doInvoke(proxy, invocation.getMethodName(), invocation.getParameterTypes(), invocation.getArguments());
  179.         ...
  180.         //将value值封装成CompletableFuture对象
  181.         CompletableFuture<Object> future = wrapWithFuture(value, invocation);
  182.         //再次转换,转换为CompletableFuture类型
  183.         CompletableFuture appResponseFuture = future.handle((obj, t) -> {
  184.         AppResponse result = new AppResponse(invocation);
  185.         ...
  186.         //将CompletableFuture封装成AsyncRpcResult返回
  187.         return new AsyncRpcResult(appResponseFuture, invocation);
  188.     }
  189.     protected abstract Object doInvoke(T proxy, String methodName, Class<?>[] parameterTypes, Object[] arguments) throws Throwable;
  190.     ...
  191. }
复制代码
[code]//-> Protocol$Adaptive.export()//-> ProtocolSerializationWrapper.export()//-> ProtocolFilterWrapper.export()//-> ProtocolListenerWrapper.export()//-> InjvmProtocol.export()public class InjvmProtocol extends AbstractProtocol implements Protocol {    ...    @Override    public  Exporter export(Invoker invoker) throws RpcException {        return new InjvmExporter(invoker, invoker.getUrl().getServiceKey(), exporterMap);    }    ...}public class InjvmExporter extends AbstractExporter {    private final String key;    //这就是在JVM里存放了    private final Map> exporterMap;    public DubboExporter(Invoker invoker, String key, Map

相关推荐

您需要登录后才可以回帖 登录 | 立即注册