Dubbo2.7.8服务启动过程源码分析

一. 环境准备

可以从git clone,导入intellij idea,子模块dubbo-demo可以调试。

也可以新建Maven工程,自写demo。推荐(要动手)。

本文以新建为例,并推荐引入nacos做为注册中心(可选其他注册中心)。

  1. 新建父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>

  1. 子模块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);
    
}
  1. 子模块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

整体目录结构:


2020-09-05_174510.png
  1. Nacos1.2.1注册中心搭建
    见上一篇文章nacos1.2.1注册中心调试环境搭建

二.启动调试(初始化)

上述工程是基于annotation方式创建的,所以启动类为AnnotationConfigApplicationContext

  1. 入口:启动类AnnotationProviderBootstrap的main方法:
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(ProviderConfiguration.class);

设置断点,并启动。

  1. 调试进入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,会做两部分操作,可实时查看控制台输出日志。

  1. 见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);
  1. 见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


image.png

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其他源码分析,包括负载均衡,路由等等。

最后编辑于 :
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

友情链接更多精彩内容