深入理解Dubbo-5.服务注册源码分析(上)

简介: 深入理解Dubbo-5.服务注册源码分析

Dubbo服务的注册流程


服务发布步骤


  • 注解
@DubboService(
        loadbalance = "random",
        cluster = "failover",
        retries = 2)
  • 注解扫描
@DubboComponentScan


思考


首先需要扫描注解,在扫描的过程中,可以拿到注解中的数据(注解的目的其实是做一个标记的功能,可以通过不同的标记去对一些类做一个分类,具体扫描哪一个注解取决于对其的关注度),然后解析注解获取对应的配置。


解析完成后,需要去发布服务,像Dubbo是基于URL驱动的,其会将所有的配置信息配置在URL的地址上,所以这一步主要做的就是URL的组装。


后面要做的事情就是将其注册到zookeeper上(相当于把服务端的相关配置信息和服务的地址信息都会保存到第三方的平台上)到了第三方平台之后,如果我的客户端要去调用的时候,可以通过第三方平台知道服务端的调用机制是什么,这些都可以在URL上识别到。


接下来就是启动服务了,根据URL中配置的协议、配置的端口去发布对应的服务。


Dubbo源码分析


Dubbo发布其实有两种形式,其实从前面介绍的博客上来说


分为 xml形式 dubbo:service 和 注解形式 @DubboService/ @Service


Dubbo注解的解析流程


DubboComponetScan


@DubboComponentScan(basePackages = "com.gupaoedu.springboot.dubbo.springbootdubbosampleprovider.services")
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(DubboComponentScanRegistrar.class)
public @interface DubboComponentScan {
}
// 这里面无非就是注册一个bean到 Spring IOC 里面
public class DubboComponentScanRegistrar implements ImportBeanDefinitionRegistrar {
    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
    // 这个就是获取我们在注解上 定义的 basePackages
        Set<String> packagesToScan = getPackagesToScan(importingClassMetadata);
        registerServiceAnnotationBeanPostProcessor(packagesToScan, registry);
        // @since 2.7.6 Register the common beans
        registerCommonBeans(registry);
    }
---------------------------------------------------------------------------
private void registerServiceAnnotationBeanPostProcessor(Set<String> packagesToScan, BeanDefinitionRegistry registry) {
    // 在这里注册了 一个叫做 ServiceAnnotationBeanPostProcessor 的bean
        BeanDefinitionBuilder builder = rootBeanDefinition(ServiceAnnotationBeanPostProcessor.class);
    // 传递一个构造参数 packagesToScan  这里也就意味着服务的注册流程和 ServiceAnnotationBeanPostProcessor bean有关系
        builder.addConstructorArgValue(packagesToScan);
        builder.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
        AbstractBeanDefinition beanDefinition = builder.getBeanDefinition();
    // 将这个bean注册
        BeanDefinitionReaderUtils.registerWithGeneratedName(beanDefinition, registry);
    }


ServiceAnnotationBeanPostProcessor


public ServiceAnnotationBeanPostProcessor(Set<String> packagesToScan) {
    super(packagesToScan);
}
// 进入super   因为实现了 BeanDefinitionRegistryPostProcessor,所以在bean装载完成之后,会触发postProcessBeanDefinitionRegistry 方法
public class ServiceClassPostProcessor implements BeanDefinitionRegistryPostProcessor, EnvironmentAware,
        ResourceLoaderAware, BeanClassLoaderAware {
    public ServiceClassPostProcessor(Set<String> packagesToScan) {
        this.packagesToScan = packagesToScan;
    }
    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
        // 注册一个基础的bean
        registerInfrastructureBean(registry, DubboBootstrapApplicationListener.BEAN_NAME, DubboBootstrapApplicationListener.class);
        Set<String> resolvedPackagesToScan = resolvePackagesToScan(packagesToScan);
        // 判断我们传过来需要扫描的路径是不是空的,如果不是空的会调用下面的方法
        if (!CollectionUtils.isEmpty(resolvedPackagesToScan)) {
            registerServiceBeans(resolvedPackagesToScan, registry);
        } else {
            if (logger.isWarnEnabled()) {
                logger.warn("packagesToScan is empty , ServiceBean registry will be ignored!");
            }
        }
    }       


注册一个DubboBootstrapApplicationListener


这个bean会在spring 容器的上下文装载完成之后,触发监听

public class DubboBootstrapApplicationListener extends OneTimeExecutionApplicationContextEventListener
        implements Ordered {
    /**
     * The bean name of {@link DubboBootstrapApplicationListener}
     *
     * @since 2.7.6
     */
    public static final String BEAN_NAME = "dubboBootstrapApplicationListener";
    private final DubboBootstrap dubboBootstrap;
    public DubboBootstrapApplicationListener() {
        this.dubboBootstrap = DubboBootstrap.getInstance();
    }
    @Override
    public void onApplicationContextEvent(ApplicationContextEvent event) {
    // 上下文刷新的时候,也就是bean装载完成的时候
        if (event instanceof ContextRefreshedEvent) {
            onContextRefreshedEvent((ContextRefreshedEvent) event);
        } else if (event instanceof ContextClosedEvent) {
            onContextClosedEvent((ContextClosedEvent) event);
        }
    }


registerServiceBeans


private void registerServiceBeans(Set<String> packagesToScan, BeanDefinitionRegistry registry) {
    // 定义一个scanner 用作扫描
        DubboClassPathBeanDefinitionScanner scanner =
                new DubboClassPathBeanDefinitionScanner(registry, environment, resourceLoader);
      // 生成一个bean的名字
        BeanNameGenerator beanNameGenerator = resolveBeanNameGenerator(registry);
        scanner.setBeanNameGenerator(beanNameGenerator);
      // 为了兼容老的版本,实际上就是把需要扫描的注解类型,设置到Scanner。
        // refactor @since 2.7.7
        serviceAnnotationTypes.forEach(annotationType -> {
            scanner.addIncludeFilter(new AnnotationTypeFilter(annotationType));
        });
      // 遍历给的包路径
        for (String packageToScan : packagesToScan) {
            // 扫描对应的路径
            // Registers @Service Bean first
            scanner.scan(packageToScan);
            // Finds all BeanDefinitionHolders of @Service whether @ComponentScan scans or not.
            // 查找@Service的所有beandefinitionholder
            // 相当于扫描所有加了 @DubboService注解的类
            Set<BeanDefinitionHolder> beanDefinitionHolders =
                    findServiceBeanDefinitionHolders(scanner, packageToScan, registry, beanNameGenerator);
            if (!CollectionUtils.isEmpty(beanDefinitionHolders)) {
                for (BeanDefinitionHolder beanDefinitionHolder : beanDefinitionHolders) {
                    registerServiceBean(beanDefinitionHolder, registry, scanner);
                }
                if (logger.isInfoEnabled()) {
                    logger.info(beanDefinitionHolders.size() + " annotated Dubbo's @Service Components { " +
                            beanDefinitionHolders +
                            " } were scanned under package[" + packageToScan + "]");
                }
            } else {
                if (logger.isWarnEnabled()) {
                    logger.warn("No Spring Bean annotating Dubbo's @Service was found under package["
                            + packageToScan + "]");
                }
            }
        }
    }


registerServiceBean


该bean和服务有关的信息,实际上都在我们刚刚定义的@DubboService

@DubboService(
        loadbalance = "random",
        cluster = "failover",
        retries = 2)
  • 服务以什么协议发布
  • 服务的负载均衡策略
  • 服务的容错策略
  • 服务发布端口
private void registerServiceBean(BeanDefinitionHolder beanDefinitionHolder, BeanDefinitionRegistry registry,
                                     DubboClassPathBeanDefinitionScanner scanner) {
    // 获取beanDefinitionHolder中的类对象
        Class<?> beanClass = resolveClass(beanDefinitionHolder); 
    // 在beanClass中查找@Service注解的存在
        Annotation service = findServiceAnnotation(beanClass);
        /**
         * The {@link AnnotationAttributes} of @Service annotation
         */
    //获取@Service注解的属性信息,包括interfaceClass等
        AnnotationAttributes serviceAnnotationAttributes = getAnnotationAttributes(service, false, false);
    // 根据@Service注解的属性信息,解析服务接口类
        Class<?> interfaceClass = resolveServiceInterfaceClass(serviceAnnotationAttributes, beanClass);
    // 使用@Service注解的属性信息,接口类和注解的服务Bean名称构建服务Bean定义
        String annotatedServiceBeanName = beanDefinitionHolder.getBeanName();
    // 根据@Service注解的属性信息和接口类生成服务Bean的名称
        AbstractBeanDefinition serviceBeanDefinition =
                buildServiceBeanDefinition(service, serviceAnnotationAttributes, interfaceClass, annotatedServiceBeanName);
        // ServiceBean Bean name
    // 使用扫描器检查候选的Bean名称和服务Bean定义是否重复
        String beanName = generateServiceBeanName(serviceAnnotationAttributes, interfaceClass);
        if (scanner.checkCandidate(beanName, serviceBeanDefinition)) { // check duplicated candidate bean
            // 如果候选Bean通过检查,将服务Bean定义注册到Bean定义注册表中
            // 通过 buildServiceBeanDefinition 得知这里面注册的就是ServiceBean
            registry.registerBeanDefinition(beanName, serviceBeanDefinition);
            // 据注册结果输出相应的日志信息,包括注册成功和重复注册的警告信息
            if (logger.isInfoEnabled()) {
                logger.info("The BeanDefinition[" + serviceBeanDefinition +
                        "] of ServiceBean has been registered with name : " + beanName);
            }
        } else {
            if (logger.isWarnEnabled()) {
                logger.warn("The Duplicated BeanDefinition[" + serviceBeanDefinition +
                        "] of ServiceBean[ bean name : " + beanName +
                        "] was be found , Did @DubboComponentScan scan to same package in many times?");
            }
        }
    }


buildServiceBeanDefinition


private AbstractBeanDefinition buildServiceBeanDefinition(Annotation serviceAnnotation,
                                                              AnnotationAttributes serviceAnnotationAttributes,
                                                              Class<?> interfaceClass,
                                                              String annotatedServiceBeanName) {
    // 通过大体阅读可以看到,其会将很多的配置信息构建到一个叫做 ServiceBean 里面 !!!
        BeanDefinitionBuilder builder = rootBeanDefinition(ServiceBean.class);
        AbstractBeanDefinition beanDefinition = builder.getBeanDefinition();
        MutablePropertyValues propertyValues = beanDefinition.getPropertyValues();
        String[] ignoreAttributeNames = of("provider", "monitor", "application", "module", "registry", "protocol",
                "interface", "interfaceName", "parameters");
        propertyValues.addPropertyValues(new AnnotationPropertyValuesAdapter(serviceAnnotation, environment, ignoreAttributeNames));
        // References "ref" property to annotated-@Service Bean
        addPropertyReference(builder, "ref", annotatedServiceBeanName);
        // Set interface
        builder.addPropertyValue("interface", interfaceClass.getName());
        // Convert parameters into map
        builder.addPropertyValue("parameters", convertParameters(serviceAnnotationAttributes.getStringArray("parameters")));
        // Add methods parameters
        List<MethodConfig> methodConfigs = convertMethodConfigs(serviceAnnotationAttributes.get("methods"));
        if (!methodConfigs.isEmpty()) {
            builder.addPropertyValue("methods", methodConfigs);
        }
        /**
         * Add {@link org.apache.dubbo.config.ProviderConfig} Bean reference
         */
        String providerConfigBeanName = serviceAnnotationAttributes.getString("provider");
        if (StringUtils.hasText(providerConfigBeanName)) {
            addPropertyReference(builder, "provider", providerConfigBeanName);
        }
        /**
         * Add {@link org.apache.dubbo.config.MonitorConfig} Bean reference
         */
        String monitorConfigBeanName = serviceAnnotationAttributes.getString("monitor");
        if (StringUtils.hasText(monitorConfigBeanName)) {
            addPropertyReference(builder, "monitor", monitorConfigBeanName);
        }
        /**
         * Add {@link org.apache.dubbo.config.ApplicationConfig} Bean reference
         */
        String applicationConfigBeanName = serviceAnnotationAttributes.getString("application");
        if (StringUtils.hasText(applicationConfigBeanName)) {
            addPropertyReference(builder, "application", applicationConfigBeanName);
        }
        /**
         * Add {@link org.apache.dubbo.config.ModuleConfig} Bean reference
         */
        String moduleConfigBeanName = serviceAnnotationAttributes.getString("module");
        if (StringUtils.hasText(moduleConfigBeanName)) {
            addPropertyReference(builder, "module", moduleConfigBeanName);
        }
        /**
         * Add {@link org.apache.dubbo.config.RegistryConfig} Bean reference
         */
        String[] registryConfigBeanNames = serviceAnnotationAttributes.getStringArray("registry");
        List<RuntimeBeanReference> registryRuntimeBeanReferences = toRuntimeBeanReferences(registryConfigBeanNames);
        if (!registryRuntimeBeanReferences.isEmpty()) {
            builder.addPropertyValue("registries", registryRuntimeBeanReferences);
        }
        /**
         * Add {@link org.apache.dubbo.config.ProtocolConfig} Bean reference
         */
        String[] protocolConfigBeanNames = serviceAnnotationAttributes.getStringArray("protocol");
        List<RuntimeBeanReference> protocolRuntimeBeanReferences = toRuntimeBeanReferences(protocolConfigBeanNames);
        if (!protocolRuntimeBeanReferences.isEmpty()) {
            builder.addPropertyValue("protocols", protocolRuntimeBeanReferences);
        }
        return builder.getBeanDefinition();
    }

最终通过上述代码,讲一个 dubbo中提供的ServiceBean注入到Spring IOC容器


ServiceBean的初始化阶段


因为我们向spring注入了一个ServiceBean 那么在spring最后实例化阶段,即执行到 finishBeanFactoryInitialization 方法的时候就会调用到getBean方法从而通过反射去实例化,那么就会调用到ServiceBean 的构造方法。看看其构造函数

public ServiceBean() {
        super();
        this.service = null;
    }

当ServiceBean初始化完成之后,会调用下面的方法.

@Override
public void afterPropertiesSet() throws Exception {
    if (StringUtils.isEmpty(getPath())) {
        if (StringUtils.isNotEmpty(beanName)
            && StringUtils.isNotEmpty(getInterface())
            && beanName.startsWith(getInterface())) {
            setPath(beanName);
        }
    }
}


DubboBootstrapApplicationListener


在Dubbo中,DubboBootstrapApplicationListener是一个Spring应用程序监听器,它在Spring应用程序启动时会监听Dubbo的启动事件。


当启动 Dubbo服务时。

public class DubboBootstrapApplicationListener extends OnceApplicationContextEventListener implements Ordered {
    /**
     * The bean name of {@link DubboBootstrapApplicationListener}
     *
     * @since 2.7.6
     */
    public static final String BEAN_NAME = "dubboBootstrapApplicationListener";
    private final DubboBootstrap dubboBootstrap;
    public DubboBootstrapApplicationListener(ApplicationContext applicationContext) {
        super(applicationContext);
        this.dubboBootstrap = DubboBootstrap.getInstance();
    }
    @Override
    public void onApplicationContextEvent(ApplicationContextEvent event) {
        if (event instanceof ContextRefreshedEvent) {
            onContextRefreshedEvent((ContextRefreshedEvent) event);
        } else if (event instanceof ContextClosedEvent) {
            onContextClosedEvent((ContextClosedEvent) event);
        }
    }
    private void onContextRefreshedEvent(ContextRefreshedEvent event) {
        dubboBootstrap.start();
    }
    private void onContextClosedEvent(ContextClosedEvent event) {
        dubboBootstrap.stop();
    }
    @Override
    public int getOrder() {
        return LOWEST_PRECEDENCE;
    }
}
// 监听的时候会进入到 onContextRefreshedEvent 里面

当开启start的时候可能会做的配置:


  • 元数据/远程配置信息的初始化
  • 拼接url()
  • 如果是dubbo协议,则启动netty server
  • 服务注册


start()

public DubboBootstrap start() {
    // 首先通过compareAndSet方法确保started标识为false,避免重复执行启动操作
        if (started.compareAndSet(false, true)) {
            ready.set(false);
            // 调用initialize方法进行初始化。
            initialize();
            if (logger.isInfoEnabled()) {
                logger.info(NAME + " is starting...");
            }
            // 1. export Dubbo Services
            // 导出Dubbo服务,即将服务暴露出去。
            exportServices();
            // Not only provider register
            // 如果不仅仅是注册提供者,并且已经导出了服务,那么还会导出MetadataService。
      // 如果需要,注册本地ServiceInstance。
            if (!isOnlyRegisterProvider() || hasExportedServices()) {
                // 2. export MetadataService
                exportMetadataService();
                //3. Register the local ServiceInstance if required
                registerServiceInstance();
            }
            referServices();
            // 如果存在异步导出的服务,会启动一个新的线程来等待异步导出完成。
            if (asyncExportingFutures.size() > 0) {
                new Thread(() -> {
                    try {
                        this.awaitFinish();
                    } catch (Exception e) {
                        logger.warn(NAME + " exportAsync occurred an exception.");
                    }
                    // 最后设置ready标识为true,表示Dubbo框架已经准备就绪。
                    ready.set(true);
                    if (logger.isInfoEnabled()) {
                        logger.info(NAME + " is ready.");
                    }
                }).start();
            } else {
                ready.set(true);
                if (logger.isInfoEnabled()) {
                    logger.info(NAME + " is ready.");
                }
            }
            if (logger.isInfoEnabled()) {
                logger.info(NAME + " has started.");
            }
        }
        return this;
    }


深入理解Dubbo-5.服务注册源码分析(中):https://developer.aliyun.com/article/1414061

目录
相关文章
|
3月前
|
存储 负载均衡 监控
深入理解Dubbo-6.服务消费源码分析(下)
深入理解Dubbo-6.服务消费源码分析
33 0
|
3月前
|
缓存 Dubbo Java
深入理解Dubbo-5.服务注册源码分析(下)
深入理解Dubbo-5.服务注册源码分析
30 0
|
3月前
|
缓存 编解码 Dubbo
深入理解Dubbo-5.服务注册源码分析(中)
深入理解Dubbo-5.服务注册源码分析
41 0
|
2月前
|
Dubbo Java 应用服务中间件
Dubbo 第四节: Spring与Dubbo整合原理与源码分析
DubboConfigConfigurationRegistrar的主要作⽤就是对propties⽂件进⾏解析并根据不同的配置项项⽣成对应类型的Bean对象。
|
3月前
|
Java Spring
深入理解Dubbo-7.服务消费调用源码分析(下)
深入理解Dubbo-7.服务消费调用源码分析
37 0
|
3月前
|
负载均衡 Dubbo 应用服务中间件
深入理解Dubbo-7.服务消费调用源码分析(中)
深入理解Dubbo-7.服务消费调用源码分析
43 0
|
3月前
|
负载均衡 算法 Dubbo
深入理解Dubbo-7.服务消费调用源码分析(上)
深入理解Dubbo-7.服务消费调用源码分析
77 0
|
3月前
|
Dubbo Java 应用服务中间件
深入理解Dubbo-6.服务消费源码分析(上)
深入理解Dubbo-6.服务消费源码分析
35 1
|
7月前
|
负载均衡 Dubbo Java
RPC框架-dubbo:架构及源码分析-初篇
在自学或面试dubbo时,相关的问题有很多,例如dubbo 的基本工作原理,这是使用过dubbo后应该知道的。包括dubbo的分层架构、长短链接选择、二进制协议支持;之后是使用方式(服务的注册、发现、调用方式),基础配置(超时时间、线程数),这些是最基本的。 在这些问题之后,就可以继续深入底层:关于连接方式,使用长连接还是短连接?为什么? dubbo的二进制协议支持哪些,之间有什么区别/优缺点等等,也可以考察在使用过程中遇到过哪些问题,是如何解决的。这些都需要深入理解,并且有真实、长时间使用经验。
148 0
|
5月前
|
负载均衡 Dubbo 应用服务中间件
微服务技术系列教程(31) - Dubbo-原理及负载均衡分析
微服务技术系列教程(31) - Dubbo-原理及负载均衡分析
56 0

热门文章

最新文章