一. 环境准备
可以从git clone,导入intellij idea,子模块dubbo-demo可以调试。
也可以新建Maven工程,自写demo。推荐(要动手)。
本文以新建为例,并推荐引入nacos做为注册中心(可选其他注册中心)。
- 新建父maven工程,pom文件如下:
<?xml version="1.0" encoding="UTF-8"?>
<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.0</modelVersion>
<groupId>org.example</groupId>
<artifactId>zp-dubbo-demo</artifactId>
<packaging>pom</packaging>
<version>1.0-SNAPSHOT</version>
<modules>
<module>demo-api</module>
<module>demo-provider-api-pattern</module>
<module>demo-consumer-api-pattern</module>
<module>dubbo-provider-annotation-pattern</module>
<module>dubbo-consumer-annotation-pattern</module>
</modules>
<dependencies>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo</artifactId>
<version>2.7.8</version>
<exclusions>
<exclusion>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-registry-nacos</artifactId>
<version>2.7.8</version>
<exclusions>
<exclusion>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>1.7.25</version>
<scope>compile</scope>
</dependency>
</dependencies>
</project>
- 子模块demo-api,用于接口共享:
pom文件如下:
<?xml version="1.0" encoding="UTF-8"?>
<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>zp-dubbo-demo</artifactId>
<groupId>org.example</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>demo-api</artifactId>
</project>
新建接口:
public interface HelloService {
public String sayHello(String user);
}
- 子模块dubbo-provider-annotation-pattern.
pom文件如下:
<?xml version="1.0" encoding="UTF-8"?>
<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>zp-dubbo-demo</artifactId>
<groupId>org.example</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>dubbo-provider-annotation-pattern</artifactId>
<dependencies>
<dependency>
<groupId>org.example</groupId>
<artifactId>demo-api</artifactId>
<version>1.0-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
</dependencies>
</project>
新建接口实现类AnnotationProviderServiceImpl:
@DubboService
public class AnnotationProviderServiceImpl implements HelloService {
private final Logger logger = LoggerFactory.getLogger(AnnotationProviderServiceImpl.class);
@Override
public String sayHello(String user) {
logger.info("from consumer " +user);
return "provider say hello to "+ user;
}
}
新建启动类AnnotationProviderBootstrap.
public class AnnotationProviderBootstrap {
public static void main(String[] args) throws IOException {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(ProviderConfiguration.class);
applicationContext.start();
System.in.read();
}
@Configuration
@EnableDubbo(scanBasePackages = "com.zp.dubbo.provider.service")
@PropertySource("classpath:/dubbo-provider.properties")
@ComponentScan(value = {"com.zp.dubbo.provider.service"})
static class ProviderConfiguration {
}
}
dubbo-provider.properties配置文件如下:
dubbo.application.name=annotation-provider2
dubbo.registry.address=nacos://192.168.1.102:8858,192.168.1.102:8848,192.168.1.102:8868
dubbo.protocol.name=dubbo
dubbo.protocol.port=20880
整体目录结构:

- Nacos1.2.1注册中心搭建
见上一篇文章nacos1.2.1注册中心调试环境搭建
二.启动调试(初始化)
上述工程是基于annotation方式创建的,所以启动类为AnnotationConfigApplicationContext
- 入口:启动类AnnotationProviderBootstrap的main方法:
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(ProviderConfiguration.class);
设置断点,并启动。
- 调试进入AnnotationConfigApplicationContext。
AnnotationConfigApplicationContext 83行:
register(annotatedClasses);这里annotatedClasses为启动类中的ProviderConfiguration
AnnotatedBeanDefinitionReader的190-192行:
将ProviderConfiguration注册进AnnotationConfigApplicationContext
BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName);
definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);
回到AnnotationConfigApplicationContext84行:
refresh();
AbstractApplicationContext的524行:
// Invoke factory processors registered as beans in the context.
invokeBeanFactoryPostProcessors(beanFactory);
// Register bean processors that intercept bean creation.
registerBeanPostProcessors(beanFactory);
上述是初始化各种Processor,会做两部分操作,可实时查看控制台输出日志。
- 见DubboBeanUtils的registerCommonBeans
// Since 2.5.7 Register @Reference Annotation Bean Processor as an infrastructure Bean
registerInfrastructureBean(registry, ReferenceAnnotationBeanPostProcessor.BEAN_NAME,
ReferenceAnnotationBeanPostProcessor.class);
// Since 2.7.4 [Feature] https://github.com/apache/dubbo/issues/5093
registerInfrastructureBean(registry, DubboConfigAliasPostProcessor.BEAN_NAME,
DubboConfigAliasPostProcessor.class);
// Since 2.7.5 Register DubboLifecycleComponentApplicationListener as an infrastructure Bean
registerInfrastructureBean(registry, DubboLifecycleComponentApplicationListener.BEAN_NAME,
DubboLifecycleComponentApplicationListener.class);
// Since 2.7.4 Register DubboBootstrapApplicationListener as an infrastructure Bean
registerInfrastructureBean(registry, DubboBootstrapApplicationListener.BEAN_NAME,
DubboBootstrapApplicationListener.class);
// Since 2.7.6 Register DubboConfigDefaultPropertyValueBeanPostProcessor as an infrastructure Bean
registerInfrastructureBean(registry, DubboConfigDefaultPropertyValueBeanPostProcessor.BEAN_NAME,
DubboConfigDefaultPropertyValueBeanPostProcessor.class);
- 见ServiceClassPostProcessor的126行:
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
// @since 2.7.5
registerInfrastructureBean(registry, DubboBootstrapApplicationListener.BEAN_NAME, DubboBootstrapApplicationListener.class);
在DubboBootstrapApplicationListener的50行设置断点。
回到AnnotationConfigApplicationContext546行:
finishRefresh();
这里会发布ContextRefreshedEvent,最终被DubboBootstrapApplicationListener监听,启动
dubboBootstrap.start();
三 Dubbo真正启动过程分析
来到DubboBootstrap的893行start方法,核心所在:
if (started.compareAndSet(false, true)) {
ready.set(false);
initialize();
if (logger.isInfoEnabled()) {
logger.info(NAME + " is starting...");
}
// 1. export Dubbo Services
exportServices();
// Not only provider register
if (!isOnlyRegisterProvider() || hasExportedServices()) {
// 2. export MetadataService
exportMetadataService();
//3. Register the local ServiceInstance if required
registerServiceInstance();
}
referServices();
initialize();主要是一些初始化操作。
重点关注exportServices
在exportServices中:
ServiceConfig被翻译成:
<dubbo:service beanName="ServiceBean:com.zp.dubbo.api.HelloService" />
sc.export()过程:
见ServiceConfig183行:
init serviceMetadata之后真正执行doExport动作,最终来到ServiceConfig304行:doExportUrls
这里做了几件事:
1.registerProvider:将HelloService放入 providers 和providersWithoutGroup。
2.获取注册中心地址:registryURLs
3.doExportUrlsFor1Protocol

4.exportLocal
这里根据不同的Protocol启动不同的Server。可调试进入DubboProtocol的export方法。
5.在RegistryProtocol中注册到注册中心
// url to registry
final Registry registry = getRegistry(originInvoker);
final URL registeredProviderUrl = getUrlToRegistry(providerUrl, registryUrl);
// decide if we need to delay publish
boolean register = providerUrl.getParameter(REGISTER_KEY, true);
if (register) {
register(registryUrl, registeredProviderUrl);
}
调试至FailbackRegistry240行:
doRegister(url);
进入NacosRegistry152行,进行注册。
进入NacosNamingService139行:registerInstance
最终NamingProxy168行registerService完成注册。
6.exported() 分发ServiceConfigExportedEvent事件
那么到此,dubbo的服务提供者注册过程分析就已经全部完成。
接下来将进行dubbo其他源码分析,包括负载均衡,路由等等。