需要前置知识,了解spring源码,springboot自动加载机制等
DubboBootstrap启动
详细信息可看 学习Dubbo源码需要了解的基础内容源码详解
DubboBootstrap 启动所需要的信息
- 添加应用程序配置
- 添加注册中心配置
- 添加协议配置
- 添加服务配置
- 启动
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 BeanregisterInfrastructureBean(registry, ReferenceAnnotationBeanPostProcessor.BEAN_NAME,ReferenceAnnotationBeanPostProcessor.class);// TODO Whether DubboConfigAliasPostProcessor can be removed ?// Since 2.7.4 [Feature] https://github.com/apache/dubbo/issues/5093registerInfrastructureBean(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 BeanregisterInfrastructureBean(registry, DubboConfigDefaultPropertyValueBeanPostProcessor.BEAN_NAME,DubboConfigDefaultPropertyValueBeanPostProcessor.class);// Dubbo config initializerregisterInfrastructureBean(registry, DubboConfigBeanInitializer.BEAN_NAME, DubboConfigBeanInitializer.class);// register infra bean if not exists laterregisterInfrastructureBean(registry, DubboInfraBeanRegisterPostProcessor.BEAN_NAME, DubboInfraBeanRegisterPostProcessor.class);
}
注册服务配置信息SercviceBean
registerServiceAnnotationPostProcessor(packagesToScan, registry);
注册了 ServiceAnnotationPostProcessor
private void registerServiceAnnotationPostProcessor(Set<String> packagesToScan, BeanDefinitionRegistry registry) {// 注册 ServiceAnnotationPostProcessorBeanDefinitionBuilder 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;// 扫描BeanscanServiceBeans(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 scansif (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/6007DubboService.class,// @since 2.7.0 the substitute @com.alibaba.dubbo.config.annotation.ServiceService.class,// @since 2.7.3 Add the compatibility for legacy Dubbo's @Service , the issue : https://github.com/apache/dubbo/issues/4330com.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);// 获取 @DubboServiceAnnotation service = findServiceAnnotation(beanClass);// 获取配置在注解@DubboService上的所有属性Map<String, Object> serviceAnnotationAttributes = AnnotationUtils.getAttributes(service, true);// 根据注解信息和类信息解析出接口信息String serviceInterface = resolveInterfaceName(serviceAnnotationAttributes, beanClass);// 拿到 @DubboSerivce修饰的类名String annotatedServiceBeanName = beanDefinitionHolder.getBeanName();// ServiceBean Bean nameString beanName = generateServiceBeanName(serviceAnnotationAttributes, serviceInterface);// 构造了关于Servicebean的 BeanDefinitionAbstractBeanDefinition serviceBeanDefinition =buildServiceBeanDefinition(serviceAnnotationAttributes, serviceInterface, annotatedServiceBeanName);// 把 关于Servicebean的 BeanDefinition 添加到spring中registerServiceBeanDefinition(beanName, serviceBeanDefinition, serviceInterface);}
buildServiceBeanDefinition
构建了一个BeanDefinition,设置他的BeanClass = ServiceBean, 每个接口都会生成一个BeanDefinition
到这里位置,就已经把所以扫描到@DubboService(包括兼容历史所需要的 @Service )注解的类,全部注册为了BeanDefinition,开始进行spring bean的初始化,开始初始化设置的ServiceBean
private AbstractBeanDefinition buildServiceBeanDefinition(Map<String, Object> serviceAnnotationAttributes,String serviceInterface,String refServiceBeanName) {// 创建 ServiceBean 的BuilderBeanDefinitionBuilder 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 finishif (!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 callssynchronized (startLock) {if (initialized) {return;}// register shutdown hookregisterShutdownHook();startConfigCenter();loadApplicationConfigs();initModuleDeployers();// @since 2.7.8startMetadataCenter();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;}// 却换模块启动状态 STARTINGonModuleStarting();//如果为初始化则初始化initialize();// export services//服务暴漏exportServices();// prepare application instance// exclude internal module to avoid wait itselfif (moduleModel != moduleModel.getApplicationModel().getInternalModule()) {applicationDeployer.prepareInternalModule();}// refer services//引用服务referServices();// if no async export/refer services, just set started//非异步启动直接转换状态为STARTEDif (asyncExportingFutures.isEmpty() && asyncReferringFutures.isEmpty()) {onModuleStarted();} else {//如果是异步启动,等待服务发布和服务引用的回调frameworkExecutorRepository.getSharedExecutor().submit(() -> {try {// wait for export finishwaitExportFinish();// wait for refer finishwaitReferFinish();} 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;
}
服务暴漏和服务拉去见 源码详解