Dubbo之SpringBoot启动源码详解

需要前置知识,了解spring源码,springboot自动加载机制等

DubboBootstrap启动

详细信息可看 学习Dubbo源码需要了解的基础内容源码详解

DubboBootstrap 启动所需要的信息

  1. 添加应用程序配置
  2. 添加注册中心配置
  3. 添加协议配置
  4. 添加服务配置
  5. 启动

SpringBoot启动Dubbo

@EnableDubbo注解 中引用了 @DubboComponentScan@EnableDubboConfig注解

@DubboComponentScan注解中引用了 @Import(DubboComponentScanRegistrar.class) 所以以DubboComponentScanRegistrar类为起点

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(DubboComponentScanRegistrar.class)
public @interface DubboComponentScan {
    String[] value() default {};
    String[] basePackages() default {};
    Class<?>[] basePackageClasses() default {};
}

DubboComponentScanRegistrar

实现自 ImportBeanDefinitionRegistrar 重写了 registerBeanDefinitions方法,在SpringBoot源码中会回调 registerBeanDefinitions方法,可见SpringBoot源码

@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {

    // initialize dubbo beans
    // 核心 初始化环境 包括注册监听器
    DubboSpringInitializer.initialize(registry);

    Set<String> packagesToScan = getPackagesToScan(importingClassMetadata);
	// 注册ServiceBean 和dubbo启动信息
    registerServiceAnnotationPostProcessor(packagesToScan, registry);
}

DubboSpringInitializer.initialize(registry) =》 调用 initContext(context, registry, beanFactory) 初始化上下文

initContext(context, registry, beanFactory) =》调用 DubboBeanUtils.registerCommonBeans(registry);注册公共使用Bean对象

DubboBeanUtils.registerCommonBeans(registry);

static void registerCommonBeans(BeanDefinitionRegistry registry) {

    registerInfrastructureBean(registry, ServicePackagesHolder.BEAN_NAME, ServicePackagesHolder.class);

    registerInfrastructureBean(registry, ReferenceBeanManager.BEAN_NAME, ReferenceBeanManager.class);

    // Since 2.5.7 Register @Reference Annotation Bean Processor as an infrastructure Bean
    registerInfrastructureBean(registry, ReferenceAnnotationBeanPostProcessor.BEAN_NAME,
        ReferenceAnnotationBeanPostProcessor.class);

    // TODO Whether DubboConfigAliasPostProcessor can be removed ?
    // Since 2.7.4 [Feature] https://github.com/apache/dubbo/issues/5093
    registerInfrastructureBean(registry, DubboConfigAliasPostProcessor.BEAN_NAME,
        DubboConfigAliasPostProcessor.class);

    // register ApplicationListeners
    // 核心,注册了部署调度监听器和应用程序监听器 
    registerInfrastructureBean(registry, DubboDeployApplicationListener.class.getName(), DubboDeployApplicationListener.class);
    registerInfrastructureBean(registry, DubboConfigApplicationListener.class.getName(), DubboConfigApplicationListener.class);

    // Since 2.7.6 Register DubboConfigDefaultPropertyValueBeanPostProcessor as an infrastructure Bean
    registerInfrastructureBean(registry, DubboConfigDefaultPropertyValueBeanPostProcessor.BEAN_NAME,
        DubboConfigDefaultPropertyValueBeanPostProcessor.class);

    // Dubbo config initializer
    registerInfrastructureBean(registry, DubboConfigBeanInitializer.BEAN_NAME, DubboConfigBeanInitializer.class);

    // register infra bean if not exists later
    registerInfrastructureBean(registry, DubboInfraBeanRegisterPostProcessor.BEAN_NAME, DubboInfraBeanRegisterPostProcessor.class);
}

注册服务配置信息SercviceBean

registerServiceAnnotationPostProcessor(packagesToScan, registry);

注册了 ServiceAnnotationPostProcessor

private void registerServiceAnnotationPostProcessor(Set<String> packagesToScan, BeanDefinitionRegistry registry) {
	// 注册 ServiceAnnotationPostProcessor
    BeanDefinitionBuilder builder = rootBeanDefinition(ServiceAnnotationPostProcessor.class);
    builder.addConstructorArgValue(packagesToScan);
    builder.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
    AbstractBeanDefinition beanDefinition = builder.getBeanDefinition();
    BeanDefinitionReaderUtils.registerWithGeneratedName(beanDefinition, registry);
}
ServiceAnnotationPostProcessor

实现了BeanDefinitionRegistryPostProcessor,所以会调用postProcessBeanDefinitionRegistry方法

@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
    this.registry = registry;
    // 扫描Bean
    scanServiceBeans(resolvedPackagesToScan, registry);
}
scanServiceBeans(resolvedPackagesToScan, registry);

这个方法就包含了注册dubbo配置的bean的逻辑了,需要扫描自定义的注解来注册到spring的ioc容器中的套路大致都是相同的,和Mybatis一样,使用spring的扩展机制来扫描自定义的注解,然后注册为BeanDefinition,即可在Spring中注册为bean

private void scanServiceBeans(Set<String> packagesToScan, BeanDefinitionRegistry registry) {

    scanned = true;
    if (CollectionUtils.isEmpty(packagesToScan)) {
        if (logger.isWarnEnabled()) {
            logger.warn(CONFIG_NO_BEANS_SCANNED, "", "", "packagesToScan is empty , ServiceBean registry will be ignored!");
        }
        return;
    }

    // 创建扫描包类
    DubboClassPathBeanDefinitionScanner scanner =
            new DubboClassPathBeanDefinitionScanner(registry, environment, resourceLoader);

    BeanNameGenerator beanNameGenerator = resolveBeanNameGenerator(registry);
    scanner.setBeanNameGenerator(beanNameGenerator);
    // 添加有 @DubboService  @Service  的过滤条件 
    for (Class<? extends Annotation> annotationType : serviceAnnotationTypes) {
        scanner.addIncludeFilter(new AnnotationTypeFilter(annotationType));
    }

    ScanExcludeFilter scanExcludeFilter = new ScanExcludeFilter();
    scanner.addExcludeFilter(scanExcludeFilter);

    for (String packageToScan : packagesToScan) {

        // avoid duplicated scans
        if (servicePackagesHolder.isPackageScanned(packageToScan)) {
            if (logger.isInfoEnabled()) {
                logger.info("Ignore package who has already bean scanned: " + packageToScan);
            }
            continue;
        }

        // Registers @Service Bean first
        // 包扫描,扫描当前包路径下所有类(因为没开 @Indexed注解 )
        scanner.scan(packageToScan);

        // 查找@Service的所有beandefinitionholder,无论@ComponentScan是否扫描  
        // 包装成 BeanDefinitionHolder 返回
        Set<BeanDefinitionHolder> beanDefinitionHolders =
                findServiceBeanDefinitionHolders(scanner, packageToScan, registry, beanNameGenerator);

        if (!CollectionUtils.isEmpty(beanDefinitionHolders)) {
            if (logger.isInfoEnabled()) {
                List<String> serviceClasses = new ArrayList<>(beanDefinitionHolders.size());
                for (BeanDefinitionHolder beanDefinitionHolder : beanDefinitionHolders) {
                    serviceClasses.add(beanDefinitionHolder.getBeanDefinition().getBeanClassName());
                }
                logger.info("Found " + beanDefinitionHolders.size() + " classes annotated by Dubbo @Service under package [" + packageToScan + "]: " + serviceClasses);
            }

            for (BeanDefinitionHolder beanDefinitionHolder : beanDefinitionHolders) {
                // 核心 核心 对 每一个包装的 beanDefinitionHolder 处理
                processScannedBeanDefinition(beanDefinitionHolder);
                servicePackagesHolder.addScannedClass(beanDefinitionHolder.getBeanDefinition().getBeanClassName());
            }
        } else {
            if (logger.isWarnEnabled()) {
                logger.warn(CONFIG_NO_ANNOTATIONS_FOUND,"No annotations were found on the class","","No class annotated by Dubbo @Service was found under package ["
                        + packageToScan + "], ignore re-scanned classes: " + scanExcludeFilter.getExcludedCount());
            }
        }

        servicePackagesHolder.addScannedPackage(packageToScan);
    }
}
@DubboService注解的扫描使用原理

这里保证文档可读性,简单介绍,详情见 Dubbo注解 详细介绍

DubboClassPathBeanDefinitionScanner 扫描包类 实现自 ClassPathBeanDefinitionScanner

在 scanServiceBeans 方法中 通过以下代码添加了 DubboService Service 注解的过滤条件,从而才scan 扫描报的时候根据过滤条件寻找类,Scan扫描包去看Spring扫描包原理

private final static List<Class<? extends Annotation>> serviceAnnotationTypes = asList(
        // @since 2.7.7 Add the @DubboService , the issue : https://github.com/apache/dubbo/issues/6007
        DubboService.class,
        // @since 2.7.0 the substitute @com.alibaba.dubbo.config.annotation.Service
        Service.class,
        // @since 2.7.3 Add the compatibility for legacy Dubbo's @Service , the issue : https://github.com/apache/dubbo/issues/4330
        com.alibaba.dubbo.config.annotation.Service.class
);
// 添加有 @DubboService  @Service  的过滤条件 
for (Class<? extends Annotation> annotationType : serviceAnnotationTypes) {
    scanner.addIncludeFilter(new AnnotationTypeFilter(annotationType));
}
…… 
scanner.scan(packageToScan);
processScannedBeanDefinition
private void processScannedBeanDefinition(BeanDefinitionHolder beanDefinitionHolder) {

    Class<?> beanClass = resolveClass(beanDefinitionHolder);
    // 获取 @DubboService
    Annotation service = findServiceAnnotation(beanClass);
    
    // 获取配置在注解@DubboService上的所有属性
    Map<String, Object> serviceAnnotationAttributes = AnnotationUtils.getAttributes(service, true);
    // 根据注解信息和类信息解析出接口信息
    String serviceInterface = resolveInterfaceName(serviceAnnotationAttributes, beanClass);
    // 拿到 @DubboSerivce修饰的类名
    String annotatedServiceBeanName = beanDefinitionHolder.getBeanName();
    
    // ServiceBean Bean name
    String beanName = generateServiceBeanName(serviceAnnotationAttributes, serviceInterface);
    // 构造了关于Servicebean的 BeanDefinition
    AbstractBeanDefinition serviceBeanDefinition =
        buildServiceBeanDefinition(serviceAnnotationAttributes, serviceInterface, annotatedServiceBeanName);
    // 把 关于Servicebean的 BeanDefinition 添加到spring中
    registerServiceBeanDefinition(beanName, serviceBeanDefinition, serviceInterface);

}

img

buildServiceBeanDefinition

构建了一个BeanDefinition,设置他的BeanClass = ServiceBean, 每个接口都会生成一个BeanDefinition

到这里位置,就已经把所以扫描到@DubboService(包括兼容历史所需要的 @Service )注解的类,全部注册为了BeanDefinition,开始进行spring bean的初始化,开始初始化设置的ServiceBean

private AbstractBeanDefinition buildServiceBeanDefinition(Map<String, Object> serviceAnnotationAttributes,
                                                          String serviceInterface,
                                                          String refServiceBeanName) {
	// 创建 ServiceBean 的Builder
    BeanDefinitionBuilder builder = rootBeanDefinition(ServiceBean.class);
	
    AbstractBeanDefinition beanDefinition = builder.getBeanDefinition();
	// 设置ServiceBean需要的相关参数,例如  protocol,ref 等
    MutablePropertyValues propertyValues = beanDefinition.getPropertyValues();

    String[] ignoreAttributeNames = of("provider", "monitor", "application", "module", "registry", "protocol",
            "methods", "interfaceName", "parameters");
	…… …… ……
    return builder.getBeanDefinition();

}
ServiceBean初始化

初始化会调用 InitializingBean的 afterPropertiesSet 方法,详解见Dubbo前置知识

DubboDeployApplicationListener

在ServiceBean初始化后 DubboDeployApplicationListener 监听器监听了 ContextRefreshedEvent 时间,在spring初始化完成后 该监听器会被执行

onApplicationEvent监听事件
@Override
public void onApplicationEvent(ApplicationContextEvent event) {
    if (nullSafeEquals(applicationContext, event.getSource())) {
        if (event instanceof ContextRefreshedEvent) {
            onContextRefreshedEvent((ContextRefreshedEvent) event);
        } else if (event instanceof ContextClosedEvent) {
            onContextClosedEvent((ContextClosedEvent) event);
        }
    }
}
onContextRefreshedEvent
private void onContextRefreshedEvent(ContextRefreshedEvent event) {
    ModuleDeployer deployer = moduleModel.getDeployer();
    Assert.notNull(deployer, "Module deployer is null");
    // start module
	// 核心 部署器启动
    Future future = deployer.start();

    // if the module does not start in background, await finish
    if (!deployer.isBackground()) {
        try {
            future.get();
        } catch (InterruptedException e) {
            logger.warn(CONFIG_FAILED_START_MODEL, "", "", "Interrupted while waiting for dubbo module start: " + e.getMessage());
        } catch (Exception e) {
            logger.warn(CONFIG_FAILED_START_MODEL, "", "", "An error occurred while waiting for dubbo module start: " + e.getMessage(), e);
        }
    }
}
DefaultModuleDeployer#start

部署器启动

@Override
public Future start() throws IllegalStateException {
    // initialize,maybe deadlock applicationDeployer lock & moduleDeployer lock
    // 初始化部署
    applicationDeployer.initialize();

    return startSync();
}
DefaultApplicationDeployer#initialize

初始化,包括配置中心,应用程序配置,元数据配置等

对应DubboBootstrap 代码启动的加载

@Override
public void initialize() {
    if (initialized) {
        return;
    }
    // Ensure that the initialization is completed when concurrent calls
    synchronized (startLock) {
        if (initialized) {
            return;
        }
        // register shutdown hook
        registerShutdownHook();

        startConfigCenter();

        loadApplicationConfigs();

        initModuleDeployers();

        // @since 2.7.8
        startMetadataCenter();

        initialized = true;

        if (logger.isInfoEnabled()) {
            logger.info(getIdentifier() + " has been initialized!");
        }
    }
}
DefaultModuleDeployer#startSync()
private synchronized Future startSync() throws IllegalStateException {
    if (isStopping() || isStopped() || isFailed()) {
        throw new IllegalStateException(getIdentifier() + " is stopping or stopped, can not start again");
    }

    try {
        if (isStarting() || isStarted()) {
            return startFuture;
        }
    	// 却换模块启动状态 STARTING
        onModuleStarting();

    	//如果为初始化则初始化
        initialize();

        // export services
        //服务暴漏
        exportServices();

        // prepare application instance
        // exclude internal module to avoid wait itself
        if (moduleModel != moduleModel.getApplicationModel().getInternalModule()) {
            applicationDeployer.prepareInternalModule();
        }

        // refer services
        //引用服务
        referServices();

        // if no async export/refer services, just set started
        //非异步启动直接转换状态为STARTED
        if (asyncExportingFutures.isEmpty() && asyncReferringFutures.isEmpty()) {
            onModuleStarted();
        } else {
            //如果是异步启动,等待服务发布和服务引用的回调
            frameworkExecutorRepository.getSharedExecutor().submit(() -> {
                try {
                    // wait for export finish
                    waitExportFinish();
                    // wait for refer finish
                    waitReferFinish();
                } catch (Throwable e) {
                    logger.warn(CONFIG_FAILED_WAIT_EXPORT_REFER, "", "", "wait for export/refer services occurred an exception", e);
                } finally {
                    onModuleStarted();
                }
            });
        }
    } catch (Throwable e) {
        onModuleFailed(getIdentifier() + " start failed: " + e, e);
        throw e;
    }
    return startFuture;
}

服务暴漏和服务拉去见 源码详解

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值