Dubbo的官网(官网有详细讲解总体架构和代码架构):
https://dubbo.incubator.apache.org/zh/docs3-v2/java-sdk/concepts-and-architecture/
Apache Dubbo 是一款 RPC 服务开发框架,用于解决微服务架构下的服务治理与通信问题,官方提供了 Java、Golang 等多语言 SDK 实现。使用 Dubbo 开发的微服务原生具备相互之间的远程地址发现与通信能力, 利用 Dubbo 提供的丰富服务治理特性,可以实现诸如服务发现、负载均衡、流量调度等服务治理诉求。Dubbo 被设计为高度可扩展,用户可以方便的实现流量拦截、选址的各种定制逻辑。
1、Dubbo的Prodiver在启动后会去注册中心registry注册内容,注册的内容包括:IP、端口、接口列表、版本等等
2、当Consumer启动的时候,自动去Registry注册中心获取到已经注册的提供者的服务信息,并且保存服务信息的缓存
3、当Provider的信息发生变化的时候或者注册中心检测到该服务已经宕机了,则自动由注册中心异步向Consumer推送通知,并且更新Consumer中的缓存
4、Consumer同步调用Provider中的方法返回结果,基于负载均衡算法进行调用
5、每隔2分钟,Provider和Consumer自动向Monitor发送访问次数,监控器进行统计
注册中心Registry:服务注册与发现
服务提供者Provider:暴露服务
服务消费者Consumer:调用远程服务
监控中心Monitor:统计服务的调用次数和调用时间
容器Container:服务执行容器
即是通过接口注册到注册中心上的,缺点就是假设接口很多的话那么注册中心注册的接口级的服务就会很多
即是通过应用服务注册到注册中心上的,优点是不管一个服务下的dubbo接口有多少,只要针对当前服务注册到注册中心就可以了
可以通过配置修改需要使用的dubbo注册模型
dubbo.application.register-mode=instance/interface
在Dubbo2.7中用的协议是dubbo协议(依赖netty),而Dubbo3.0用的就是Triple协议
Triple 是 Dubbo3 提出的基于 HTTP2 的开放协议,旨在解决 Dubbo2 私有协议带来的互通性问题。相比于原有 Dubbo2 协议,Triple 有以下优势
dubbo.protocol.name=dubbo/tri
dubbo.protocol.port=20880
<dependency>
<groupId>org.apache.dubbogroupId>
<artifactId>dubbo-rpc-tripleartifactId>
<version>3.0.7version>
dependency>
SPI又叫做Servcie product interface(服务提供接口),根据 Java 的 SPI 规范,我们可以定义一个服务接口,具体的实现由对应的实现者去提供,即服务提供者。然后在使用的时候再根据 SPI 的规范去获取对应的服务提供者的服务实现。通过 SPI 服务加载机制进行服务的注册和发现,可以有效的避免在代码中将服务提供者写死。从而可以基于接口编程,实现模块间的解耦。
API的调用方只能依赖提供方的实现
SPI的调用方可以自定义替换API提供的默认实现(如同定制化的API一样)
Service:是一个公开的接口或者抽象类,定义了一个抽象的功能模块
Service provider:service接口的一个实现类
ExtensionLoader:SPI机制中的核心组件,负责在运行时通过load方法发现并加载 service provider,和jdk不一样的是,dubbo的加载器解决了并发的问题
大概的执行流程和JDK的一致,不同的是加载器的执行流程不同
Service:是一个公开的接口或者抽象类,定义了一个抽象的功能模块
Service provider:service接口的一个实现类
ServiceLoader:SPI机制中的核心组件,负责在运行时通过load方法发现并加载 service provider,ServiceLoader没有额外的加锁机制,存在并发问题。获取对应的实现类不够灵活,程序默认迭代获取接口的所有实现类,所以每次都要加载和实例化所有的实现类。
1、服务提供方对外提供一个公共的接口
2、服务的扩展方实现结合业务可以实现该接口,然后打包成第三方的jar包
3、服务扩展方需要在根目录下创建/METF_INF/services文档命名规范则为公共接口的全路径
4、在类加载执行的时候底层会通过serviceLoader查找哪个第三方实现了该接口,并且调用该接口的实现类从而完成扩展
1、需要遍历所有实现并实例化,浪费资源空间
2、没有使用缓存每次load都需要重新加载
1、给每个实现类配了个名字,通过名字去文件里面找到对应的实现类的全限定名然后加载实例化,按需加载
2、增加了缓存存储实,提高读取性能
3、提供了对ioc和aop等高级功能的支持,以实现更多类型的扩展
Dubbo是通过URL来作为约定的参数类型,作为配置总线
例如
dubbo://127.0.0.1:2181/com.alibaba.dubbo.registry.RegistryService?application=demo-provider&dubbo=2.0.2&pid=7960&qos.port=22222®istry=zookeeper×tamp=1598624821286
服务暴露的过程起始于 Spring IOC 容器刷新完成之时,监听到对应的事件ContextRefreshedEvent,这个事件就是服务暴露的启动点,具体的流程就是根据配置得到 URL,再利用 Dubbo SPI 机制根据 URL 的参数选择对应的实现类,实现扩展。通过 javassist 代理对象封装 实现类,统一暴露出 Invoker 使得调用方便,屏蔽底层实现细节,然后封装成 exporter 存储起来,等待消费者的调用,并且根据URL将服务提供者注册到注册中心,使得消费者可以获取服务提供者的信息。
Invoker是Dubbo中的实体域,也就是真实存在的。其他模型都向它靠拢或转换成它,它也就代表一个可执行体,可向它发起invoke调用。在服务提供方,Invoker用于调用服务提供类。在服务消费方,Invoker用于执行远程调用
DubboMetadataServiceExporter类下的export()方法
public List<URL> export() {
if (this.serviceConfig == null || !this.serviceConfig.isExported()) {
// 设置服务配置的相关参数
this.serviceConfig = new ServiceConfig();
this.serviceConfig.setInterface(DubboMetadataService.class);
this.serviceConfig.setVersion("1.0.0");
this.serviceConfig.setGroup(this.currentApplicationName);
this.serviceConfig.setRef(this.dubboMetadataService.getIfAvailable());
this.serviceConfig.setApplication(this.applicationConfig);
this.serviceConfig.setProtocol((ProtocolConfig)this.protocolConfigSupplier.get());
// 暴露方法,重点方法
this.serviceConfig.export();
if (this.logger.isInfoEnabled()) {
this.logger.info("The Dubbo service[{}] has been exported.", this.serviceConfig.toString());
}
}
// 返回暴露的url
return this.serviceConfig.getExportedUrls();
}
public synchronized void export() {
// 是否需要暴露
if (this.shouldExport()) {
// 是否是延迟暴露
if (this.shouldDelay()) {
DELAY_EXPORT_EXECUTOR.schedule(this::doExport, (long)this.getDelay(), TimeUnit.MILLISECONDS);
} else {
// 直接暴露
this.doExport();
}
}
}
protected synchronized void doExport() {
// 是否已经暴露
if (this.unexported) {
throw new IllegalStateException("The service " + this.interfaceClass.getName() + " has already unexported!");
// 是否还没有暴露
} else if (!this.exported) {
// 暴露url
this.doExportUrls();
}
}
private void doExportUrls() {
// 通过loadRegistries方法组装【注册中心】的url
List<URL> registryURLs = ConfigValidationUtils.loadRegistries(this, true);
// 遍历当前对应的协议
Iterator var4 = this.protocols.iterator();
while(var4.hasNext()) {
ProtocolConfig protocolConfig = (ProtocolConfig)var4.next();
// 真正的进入了服务暴露的方法中
this.doExportUrlsFor1Protocol(protocolConfig, registryURLs);
}
}
private void doExportUrlsFor1Protocol(ProtocolConfig protocolConfig, List<URL> registryURLs) {
// 判断是否有协议,若无则默认为dubbo
String name = protocolConfig.getName();
if (StringUtils.isEmpty(name)) {
name = "dubbo";
}
// 获取范围,判断是否是远程暴露还是本地暴露
scope = url.getParameter("scope");
// 如果范围什么都没有则跳出判断
if (!"none".equalsIgnoreCase(scope)) {
// 本地暴露
if (!"remote".equalsIgnoreCase(scope)) {
this.exportLocal(url);
}
// 远程暴露
if (!"local".equalsIgnoreCase(scope)) {
// 若【注册中心】的url不为空
if (CollectionUtils.isNotEmpty(registryURLs)) {
var10 = registryURLs.iterator();
while(var10.hasNext()) {
URL registryURL = (URL)var10.next();
// 若不是injvm协议
if (!"injvm".equalsIgnoreCase(url.getProtocol())) {
url = url.addParameterIfAbsent("dynamic", registryURL.getParameter("dynamic"));
URL monitorUrl = ConfigValidationUtils.loadMonitor(this, registryURL);
if (monitorUrl != null) {
url = url.addParameterAndEncoded("monitor", monitorUrl.toFullString());
}
if (logger.isInfoEnabled()) {
if (url.getParameter("register", true)) {
logger.info("Register dubbo service " + this.interfaceClass.getName() + " url " + url + " to registry " + registryURL);
} else {
logger.info("Export dubbo service " + this.interfaceClass.getName() + " to url " + url);
}
}
String proxy = url.getParameter("proxy");
if (StringUtils.isNotEmpty(proxy)) {
registryURL = registryURL.addParameter("proxy", proxy);
}
// 关键方法!!!!!!!!!
// 将实现类和接口以及url通过javassist或者jdk动态代理生成invoker对象
Invoker<?> invoker = PROXY_FACTORY.getInvoker(this.ref, this.interfaceClass, registryURL.addParameterAndEncoded("export", url.toFullString()));
// 生成包装对象
DelegateProviderMetaDataInvoker wrapperInvoker = new DelegateProviderMetaDataInvoker(invoker, this);
// 通过协议实现类将wrapperInvoker对象生成exporter对象,再将服务提供者注册到注册中心上
Exporter<?> exporter = PROTOCOL.export(wrapperInvoker);
this.exporters.add(exporter);
}
}
// 若【注册中心】的url为空
} else {
if (logger.isInfoEnabled()) {
logger.info("Export dubbo service " + this.interfaceClass.getName() + " to url " + url);
}
Invoker<?> invoker = PROXY_FACTORY.getInvoker(this.ref, this.interfaceClass, url);
DelegateProviderMetaDataInvoker wrapperInvoker = new DelegateProviderMetaDataInvoker(invoker, this);
Exporter<?> exporter = PROTOCOL.export(wrapperInvoker);
this.exporters.add(exporter);
}
}
}
this.urls.add(url);
}
服务的引入和服务的暴露一样,也是通过 spring 自定义标签机制解析生成对应的 Bean,Provider Service 对应解析的是 ServiceBean 而 Consumer Reference 对应的是 ReferenceBean。
public class ReferenceBean<T> extends ReferenceConfig<T> implements FactoryBean, ApplicationContextAware, InitializingBean, DisposableBean {
...
}
饿汉式是通过实现 Spring 的InitializingBean
接口中的 afterPropertiesSet
方法,容器通过调用 ReferenceBean
的 afterPropertiesSet
方法时引入服务。
懒汉式是只有当这个服务被注入到其他类中时启动引入流程,也就是说用到了才会开始服务引入。默认情况下,Dubbo 使用懒汉式引入服务,如果需要使用饿汉式,可通过配置 dubbo:reference 的 init 属性开启。
不知道大家是否还有印象,之前服务暴露的流程每个服务都会通过搞一个本地暴露,走 injvm 协议(当然你要是 scope = remote 就没本地引用了),因为存在一个服务端既是 Provider 又是 Consumer 的情况,然后有可能自己会调用自己的服务,因此就弄了一个本地引入,这样就避免了远程网络调用的开销。所以服务引入会先去本地缓存找找看有没有本地服务
这个其实就是平日测试的情况下用用,不需要启动注册中心,由 Consumer 直接配置写死 Provider 的地址,然后直连即可
这个就是重点了,Consumer 通过注册中心得知 Provider 的相关信息,然后进行服务的引入,这里还包括多注册中心,同一个服务多个提供者的情况,如何抉择如何封装,如何进行负载均衡、容错并且让使用者无感知,这就是个技术活。
相信分析下来整个流程不难的,总结地说无非就是通过配置组成 URL ,然后通过自适应得到对于的实现类进行服务引入,如果是注册中心那么会向注册中心注册自己的信息,然后订阅注册中心相关信息,得到远程 provider
的 ip 等信息,再通过netty
客户端进行连接。并且通过directory
和 cluster
进行底层多个服务提供者的屏蔽、容错和负载均衡等,这个之后文章会详细分析,最终得到封装好的 invoker
再通过动态代理封装得到代理类,让接口调用者无感知的调用方法。
public Object getObject() {
return this.get();
}
public synchronized T get() {
if (this.destroyed) {
throw new IllegalStateException("The invoker of ReferenceConfig(" + this.url + ") has already destroyed!");
} else {
// 若得到的ref引用对象为空则初始化
if (this.ref == null) {
this.init();
}
return this.ref;
}
}
public synchronized void init() {
if (!this.initialized) {
// 前置操作:通过配置生成map
// 生成代理对象(由invoker对象包装而成的)
this.ref = this.createProxy(map);
}
}
private T createProxy(Map<String, String> map) {
URL u;
// 若是本地引入
if (this.shouldJvmRefer(map)) {
// 手动创建一个url
URL url = (new URL("injvm", "127.0.0.1", 0, this.interfaceClass.getName())).addParameters(map);
// 利用SPI通过协议实现类生成对应的invoker对象
this.invoker = REF_PROTOCOL.refer(this.interfaceClass, url);
// 若是远程引入,则做一系列操作合并生成URL
} else {
this.urls.clear();
// 若配置了url,这个URL即直连的地址,或者注册中心的地址
if (this.url != null && this.url.length() > 0) {
String[] us = CommonConstants.SEMICOLON_SPLIT_PATTERN.split(this.url);
if (us != null && us.length > 0) {
for (int var17 = 0; var17 < var14; ++var17) {
// 如果是注册中心地址将map转换为查询字符串,并作为refer参数的值添加到url中
if (UrlUtils.isRegistry(url)) {
this.urls.add(url.addParameterAndEncoded("refer", StringUtils.toQueryString(map)));
// 如果是点对点会合并url,移除服务提供者的一些配置
} else {
this.urls.add(ClusterUtils.mergeUrl(url, map));
}
}
}
// 若没有配置url,走的就是注册中心引入远程服务了
} else if (!"injvm".equalsIgnoreCase(this.getProtocol())) {
this.checkRegistry();
// 加载注册中心的地址
List<URL> us = ConfigValidationUtils.loadRegistries(this, false);
if (CollectionUtils.isNotEmpty(us)) {
// 遍历地址,并且将map转换为查询字符串,并作为refer参数的值添加到url中
for(Iterator var3 = us.iterator(); var3.hasNext(); this.urls.add(u.addParameterAndEncoded("refer", StringUtils.toQueryString(map)))) {
...
}
}
}
// 若地址只有一个,则利用SPI通过协议实现类生成对应的invoker对象
if (this.urls.size() == 1) {
this.invoker = REF_PROTOCOL.refer(this.interfaceClass, (URL)this.urls.get(0));
} else {
// 有多个 URL 的时候,先遍历构建出 invoker 然后再由 StaticDirectory 封装一下,然后通过 cluster 进行合并,只暴露出一个 invoker
List<Invoker<?>> invokers = new ArrayList();
URL registryURL = null;
Iterator var16 = this.urls.iterator();
while(var16.hasNext()) {
monitorUrl = (URL)var16.next();
invokers.add(REF_PROTOCOL.refer(this.interfaceClass, monitorUrl));
if (UrlUtils.isRegistry(monitorUrl)) {
registryURL = monitorUrl;
}
}
if (registryURL != null) {
u = registryURL.addParameterIfAbsent("cluster", "zone-aware");
this.invoker = CLUSTER.join(new StaticDirectory(u, invokers));
} else {
this.invoker = CLUSTER.join(new StaticDirectory(invokers));
}
}
}
// 将invoker对象封装并生成代理对象
return PROXY_FACTORY.getProxy(this.invoker, ProtocolUtils.isGeneric(this.generic));
}
调用某个接口的方法会调用服务引用生成的代理类,然后会从集群中经过路由的过滤、负载均衡机制选择一个invoker发起远程调用,此时会记录此请求和请求的ID等待服务端的响应
服务端接收请求之后会通过参数找到之前服务暴露存储的map,得到相应的exporter,然后最终调用真正的实现类,在组装好结果返回,这个响应会带上之前请求的ID
消费者在响应之后会通过ID去找之前记录的请求,找到请求之后将响应塞到对应的Future中,唤醒等待的线程,最后消费者得到响应
在多协议或者多注册中心进行服务暴露的时候才会有可能生成多个invoker对象
1、Failover Cluster失败自动切换:dubbo的默认容错方案,当调用失败时自动切换到其他可用的节点,具体的重试次数和间隔时间可通过引用服务的时候配置,默认重试次数为1也就是只调用一次。
2、Failback Cluster失败重新恢复:在调用失败,记录日志和调用信息,然后返回空结果给consumer,并且通过定时任务每隔5秒对失败的调用进行重试
3、Failfast Cluster快速失败:只会调用一次,失败后立刻抛出异常
4、Failsafe Cluster失败安全:调用出现异常,记录日志不抛出,返回空结果
5、Forking Cluster并行调用多个服务提供者:通过线程池创建多个线程,并发调用多个provider,结果保存到阻塞队列,只要有一个provider成功返回结果,就会立刻返回结果
6、Broadcast Cluster广播模式:逐个调用每个provider,如果其中一台报错,在循环调用结束后,抛出异常
1、dubbo 默认协议:
2、rmi 协议:
3、hessian 协议:
4、http 协议:
5、webservice 协议:
6、thrift 协议:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0modelVersion>
<groupId>com.zhouyonggroupId>
<artifactId>MyDubboRpcartifactId>
<version>1.0-SNAPSHOTversion>
<packaging>pompackaging>
<modules>
<module>DubboProviderOnemodule>
<module>DubboProviderTwomodule>
<module>DubboConsumerOnemodule>
<module>DubboRpcInterfacemodule>
<module>DubboProviderThreemodule>
modules>
<name>MyDubboRpcname>
<properties>
<junit.version>4.11junit.version>
<nacos.version>2.2.1.RELEASEnacos.version>
<web.version>2.2.5.RELEASEweb.version>
<lombok.version>1.18.16lombok.version>
<httpclient.version>4.5.4httpclient.version>
<rpc.version>1.0-SNAPSHOTrpc.version>
properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>junitgroupId>
<artifactId>junitartifactId>
<version>${junit.version}version>
<scope>testscope>
dependency>
<dependency>
<groupId>com.alibaba.cloudgroupId>
<artifactId>spring-cloud-starter-alibaba-nacos-configartifactId>
<version>${nacos.version}version>
dependency>
<dependency>
<groupId>com.alibaba.cloudgroupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discoveryartifactId>
<version>${nacos.version}version>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
<version>${web.version}version>
dependency>
<dependency>
<groupId>com.alibaba.cloudgroupId>
<artifactId>spring-cloud-starter-dubboartifactId>
<version>${nacos.version}version>
dependency>
<dependency>
<groupId>org.apache.httpcomponentsgroupId>
<artifactId>httpclientartifactId>
<version>${httpclient.version}version>
<scope>compilescope>
dependency>
<dependency>
<groupId>org.projectlombokgroupId>
<artifactId>lombokartifactId>
<version>${lombok.version}version>
dependency>
<dependency>
<groupId>com.zhouyonggroupId>
<artifactId>DubboRpcInterfaceartifactId>
<version>${rpc.version}version>
dependency>
dependencies>
dependencyManagement>
project>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>MyDubboRpcartifactId>
<groupId>com.zhouyonggroupId>
<version>1.0-SNAPSHOTversion>
parent>
<modelVersion>4.0.0modelVersion>
<artifactId>DubboProviderOneartifactId>
<name>DubboProviderOnename>
<dependencies>
<dependency>
<groupId>junitgroupId>
<artifactId>junitartifactId>
<version>${junit.version}version>
<scope>testscope>
dependency>
<dependency>
<groupId>com.alibaba.cloudgroupId>
<artifactId>spring-cloud-starter-alibaba-nacos-configartifactId>
dependency>
<dependency>
<groupId>com.alibaba.cloudgroupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discoveryartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>com.alibaba.cloudgroupId>
<artifactId>spring-cloud-starter-dubboartifactId>
dependency>
<dependency>
<groupId>org.apache.httpcomponentsgroupId>
<artifactId>httpclientartifactId>
<scope>compilescope>
dependency>
<dependency>
<groupId>org.projectlombokgroupId>
<artifactId>lombokartifactId>
dependency>
<dependency>
<groupId>com.zhouyonggroupId>
<artifactId>DubboRpcInterfaceartifactId>
dependency>
dependencies>
project>
spring:
application:
name: dubbo-provider-one
cloud:
nacos:
# nacos服务注册与发现
discovery:
server-addr: localhost:8848
# nacos配置中心
config:
server-addr: localhost:8848
file-extension: yml # 指定为yaml格式或者properties都行
server:
port: 8081
# dubbo 相关配置
dubbo:
# application:
# id: dubbo-provider-one
scan:
# dubbo 服务扫描基准包
base-packages: com.zhouyong.provider
protocol:
# dubbo 协议
name: dubbo
# dubbo 协议端口( -1 表示自增端口,从 20880 开始)
port: -1
registry:
# 注册中心地址
address: nacos://localhost:8848
provider:
# 负载均衡,轮询、随机random,最少活跃数leastActive
loadbalance: roundrobin
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0modelVersion>
<parent>
<groupId>com.zhouyonggroupId>
<artifactId>MyDubboRpcartifactId>
<version>1.0-SNAPSHOTversion>
parent>
<groupId>com.zhouyonggroupId>
<artifactId>DubboConsumerartifactId>
<version>1.0-SNAPSHOTversion>
<name>DubboConsumername>
<dependencies>
<dependency>
<groupId>junitgroupId>
<artifactId>junitartifactId>
<version>${junit.version}version>
<scope>testscope>
dependency>
<dependency>
<groupId>com.alibaba.cloudgroupId>
<artifactId>spring-cloud-starter-alibaba-nacos-configartifactId>
dependency>
<dependency>
<groupId>com.alibaba.cloudgroupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discoveryartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>com.alibaba.cloudgroupId>
<artifactId>spring-cloud-starter-dubboartifactId>
dependency>
<dependency>
<groupId>org.apache.httpcomponentsgroupId>
<artifactId>httpclientartifactId>
<scope>compilescope>
dependency>
<dependency>
<groupId>org.projectlombokgroupId>
<artifactId>lombokartifactId>
dependency>
<dependency>
<groupId>com.zhouyonggroupId>
<artifactId>DubboRpcInterfaceartifactId>
dependency>
dependencies>
project>
spring:
application:
name: dubbo-consumer-one
cloud:
nacos:
# nacos服务注册与发现
discovery:
server-addr: localhost:8848
# nacos配置中心
config:
server-addr: localhost:8848
file-extension: yml # 指定为yaml格式或者properties都行
server:
port: 8083
# dubbo 相关配置
dubbo:
# application:
# id: dubbo-consumer-one
protocol:
# dubbo 协议
name: dubbo
# dubbo 协议端口( -1 表示自增端口,从 20880 开始)
port: -1
registry:
# 注册中心地址
address: nacos://localhost:8848
cloud:
# 用于服务消费方订阅服务提供方的应用名称的列表,若需订阅多应用,使用 "," 分割。 不推荐使用默认值为 "*",它将订阅所有应用。
subscribed-services: dubbo-provider-one,dubbo-provider-two,dubbo-provider-three
consumer:
# 启动检查服务是否存在(默认true),建议关闭,不然服务不存在有可能报错
check: false
# 设置超时时间 ms
timeout: 50000
# 设置重试次数(全局),如果不想全局设置,可以在调用方按需指定
retries: 0
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0modelVersion>
<parent>
<artifactId>MyDubboRpcartifactId>
<groupId>com.zhouyonggroupId>
<version>1.0-SNAPSHOTversion>
parent>
<groupId>com.zhouyonggroupId>
<artifactId>DubboRpcInterfaceartifactId>
<version>1.0-SNAPSHOTversion>
<name>DubboRpcInterfacename>
<dependencies>
<dependency>
<groupId>junitgroupId>
<artifactId>junitartifactId>
<version>4.11version>
<scope>testscope>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>org.projectlombokgroupId>
<artifactId>lombokartifactId>
dependency>
dependencies>
project>
gitee地址:https://gitee.com/zhouyongdage/myrpc.git
1、需要创建服务生产端和服务消费端
2、创建需要对外服务的接口以及接口的实现
3、需要将这些接口注册到注册中心中(即一个静态的map池中),这样接口可以暴露给消费端调用
4、消费端发起请求的时候需要携带调用的信息,例如调用的是哪个接口、哪个方法、哪些参数、以及参数的类型
5、需要创建一个对所有请求的拦截器
6、在消费端调用接口的时候需要对生产端的接口创建代理对象
7、对拦截到请求的参数信息进行反射调用方法并且invoke获得结果