服务注册流程分析01

简介: 在填充该 ServiceBean 的时候会将对应的那个声明了注解的 bean 设置到 ServiceBean 中。剩下的流程放置到下一篇文章中

在第一篇文章中、我们可以看到

@DubboService(version = "1.0.0")
public class DefaultDemoService implements DemoService {
    /**
     * The default value of ${dubbo.application.name} is ${spring.application.name}
     */
    @Value("${dubbo.application.name}")
    private String serviceName;
    public String sayHello(String name) {
        return String.format("[%s] : Hello, %s", serviceName, name);
    }
}
复制代码
@EnableDubbo
@SpringBootApplication
public class DubboProviderDemo {
    public static void main(String[] args) {
        ConfigurableApplicationContext run = SpringApplication.run(DubboProviderDemo.class, args);
        System.out.println();
    }
}
复制代码


只要使用 DubboReferenc 注解就可以将该接口暴露到服务注册中心上面

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
@EnableDubboConfig
@DubboComponentScan
public @interface EnableDubbo {
..............
.......
复制代码
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(DubboComponentScanRegistrar.class)
public @interface DubboComponentScan {
复制代码


我们看一下 DubboComponentScanRegistrar

public class DubboComponentScanRegistrar implements ImportBeanDefinitionRegistrar {
    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
        Set<String> packagesToScan = getPackagesToScan(importingClassMetadata);
        registerServiceAnnotationBeanPostProcessor(packagesToScan, registry);
        // @since 2.7.6 Register the common beans
        registerCommonBeans(registry);
    }
复制代码


registerServiceAnnotationBeanPostProcessor 注册一个 BeanPostProcessor

private void registerServiceAnnotationBeanPostProcessor(Set<String> packagesToScan, BeanDefinitionRegistry registry) {
    BeanDefinitionBuilder builder = rootBeanDefinition(ServiceAnnotationBeanPostProcessor.class);
    builder.addConstructorArgValue(packagesToScan);
    builder.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
    AbstractBeanDefinition beanDefinition = builder.getBeanDefinition();
    BeanDefinitionReaderUtils.registerWithGeneratedName(beanDefinition, registry);
}
复制代码


registerCommonBeans 注册一些其他需要用的 Bean。其中 ReferenceAnnotationBeanPostProcessor 就是服务消费方的关键 bean

static void registerCommonBeans(BeanDefinitionRegistry registry) {
    // 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);
}
复制代码


那么对于服务提供者、ServiceAnnotationBeanPostProcessor 就是服务注册的入口了。

xml 配置文件请看 DubboNamespaceHandler


这个类看起来啥屁事都没做

public class ServiceAnnotationBeanPostProcessor extends ServiceClassPostProcessor {
    public ServiceAnnotationBeanPostProcessor(String... packagesToScan) {
        this(Arrays.asList(packagesToScan));
    }
    public ServiceAnnotationBeanPostProcessor(Collection<String> packagesToScan) {
        this(new LinkedHashSet<>(packagesToScan));
    }
    public ServiceAnnotationBeanPostProcessor(Set<String> packagesToScan) {
        super(packagesToScan);
    }
}
复制代码


直接去它的父类 ServiceClassPostProcessor

public class ServiceClassPostProcessor implements BeanDefinitionRegistryPostProcessor, EnvironmentAware,
        ResourceLoaderAware, BeanClassLoaderAware {
复制代码


发现其继承了不少接口、其中 BeanDefinitionRegistryPostProcessor 为 Spring 注册完 Spring BeanDefinition 之后的回调接口

直接看它实现的方法

@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
    // @since 2.7.5
    registerBeans(registry, DubboBootstrapApplicationListener.class);
    Set<String> resolvedPackagesToScan = resolvePackagesToScan(packagesToScan);
    if (!CollectionUtils.isEmpty(resolvedPackagesToScan)) {
        registerServiceBeans(resolvedPackagesToScan, registry);
    }
    }
}
复制代码
private void registerServiceBeans(Set<String> packagesToScan, BeanDefinitionRegistry registry) {
    DubboClassPathBeanDefinitionScanner scanner =
            new DubboClassPathBeanDefinitionScanner(registry, environment, resourceLoader);
    BeanNameGenerator beanNameGenerator = resolveBeanNameGenerator(registry);
    scanner.setBeanNameGenerator(beanNameGenerator);
    // 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.
        Set<BeanDefinitionHolder> beanDefinitionHolders =
                findServiceBeanDefinitionHolders(scanner, packageToScan, registry, beanNameGenerator);
        if (!CollectionUtils.isEmpty(beanDefinitionHolders)) {
            for (BeanDefinitionHolder beanDefinitionHolder : beanDefinitionHolders) {
                registerServiceBean(beanDefinitionHolder, registry, scanner);
            }
        } 
      ..........
    }
复制代码

   registerBeans(registry, DubboBootstrapApplicationListener.class);

这里会注册一个 Spring 事件监听、对于后续注册服务到注册中心起着触发的作用


上面代码的大意就是扫描路径下、在类上有下面三个注解的类

private final static List<Class<? extends Annotation>> serviceAnnotationTypes = asList(
  DubboService.class,
  Service.class,
  com.alibaba.dubbo.config.annotation.Service.class
);
复制代码


registerServiceBean 关键点在这里

private void registerServiceBean(BeanDefinitionHolder beanDefinitionHolder, BeanDefinitionRegistry registry,
                                 DubboClassPathBeanDefinitionScanner scanner) {
    Class<?> beanClass = resolveClass(beanDefinitionHolder);
    Annotation service = findServiceAnnotation(beanClass);
    AnnotationAttributes serviceAnnotationAttributes = getAnnotationAttributes(service, false, false);
    Class<?> interfaceClass = resolveServiceInterfaceClass(serviceAnnotationAttributes, beanClass);
    String annotatedServiceBeanName = beanDefinitionHolder.getBeanName();
    AbstractBeanDefinition serviceBeanDefinition =
            buildServiceBeanDefinition(service, serviceAnnotationAttributes, interfaceClass, annotatedServiceBeanName);
    // ServiceBean Bean name
    String beanName = generateServiceBeanName(serviceAnnotationAttributes, interfaceClass);
    if (scanner.checkCandidate(beanName, serviceBeanDefinition)) { // check duplicated candidate bean
     // 注册到 Spring   
       registry.registerBeanDefinition(beanName, serviceBeanDefinition);
    } 
}
复制代码
private AbstractBeanDefinition buildServiceBeanDefinition(Annotation serviceAnnotation,
                                                          AnnotationAttributes serviceAnnotationAttributes,
                                                          Class<?> interfaceClass,
                                                          String annotatedServiceBeanName) {
    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);
    }
  ...........
}
复制代码

网络异常,图片无法展示
|


ServiceBean 这个 bean 就是 Dubbo 服务提供者的关键。

我们为每个声明了 Dubbo 注解的 bean 再额外注册了一个 ServiceBean 、并且会将这个 bean 赋值到 ServiceBean 的 ref 变量中

addPropertyReference(builder, "ref", annotatedServiceBeanName);         
复制代码


BeanDefinitionValueResolver

public Object resolveValueIfNecessary(Object argName, @Nullable Object value) {
   // We must check each value to see whether it requires a runtime reference
   // to another bean to be resolved.
   if (value instanceof RuntimeBeanReference) {
      RuntimeBeanReference ref = (RuntimeBeanReference) value;
      return resolveReference(argName, ref);
   }
复制代码
@Nullable
private Object resolveReference(Object argName, RuntimeBeanReference ref) {
   try {
      Object bean;
      Class<?> beanType = ref.getBeanType();
      ........
      else {
         String resolvedName;
        ........
         else {
            resolvedName = String.valueOf(doEvaluate(ref.getBeanName()));
            bean = this.beanFactory.getBean(resolvedName);
         }
         this.beanFactory.registerDependentBean(resolvedName, this.beanName);
      }
      if (bean instanceof NullBean) {
         bean = null;
      }
      return bean;
   }
   catch (BeansException ex) {
      throw new BeanCreationException(
            this.beanDefinition.getResourceDescription(), this.beanName,
            "Cannot resolve reference to bean '" + ref.getBeanName() + "' while setting " + argName, ex);
   }
}
复制代码


在填充该 ServiceBean 的时候会将对应的那个声明了注解的 bean 设置到 ServiceBean 中。


剩下的流程放置到下一篇文章中



目录
相关文章
EMQ
|
Linux 网络性能优化
MQTT 5.0 报文解析 03:SUBSCRIBE 与 UNSUBSCRIBE
在 MQTT 中,SUBSCRIBE 报文用于发起订阅请求,SUBACK 报文用于返回订阅结果。而 UNSUBSCRIBE 和 UNSUBACK 报文则在取消订阅时使用。相比于取消订阅,订阅操作更加常用。不过在本文中,我们仍然会一并介绍订阅与取消订阅报文的结构与组成。
EMQ
762 92
MQTT 5.0 报文解析 03:SUBSCRIBE 与 UNSUBSCRIBE
|
消息中间件 负载均衡 中间件
【Alibaba中间件技术系列】「RocketMQ技术专题」让我们一起探索一下DefaultMQPullConsumer的实现原理及源码分析
【Alibaba中间件技术系列】「RocketMQ技术专题」让我们一起探索一下DefaultMQPullConsumer的实现原理及源码分析
370 80
【Alibaba中间件技术系列】「RocketMQ技术专题」让我们一起探索一下DefaultMQPullConsumer的实现原理及源码分析
|
运维 监控 Devops
图解 DevOps 流程,7 大关键步骤总结,非常详细!
本文详解 DevOps 流程的 7 大关键步骤,快速掌握 DevOps 的核心实践。关注【mikechen的互联网架构】,10年+BAT架构经验分享。
图解 DevOps 流程,7 大关键步骤总结,非常详细!
|
人工智能 开发工具 计算机视觉
AI计算机视觉笔记十:结印动作识别
该项目基于恩培大佬的《火影结印识别》小项目,使用yolov5实现手势识别功能。项目包含数据集准备、模型训练和代码实现,可在无GPU环境下运行。代码利用状态机检测手势序列,完成特定结印后触发音效播放。[GitHub地址](https://github.com/enpeizhao/CVprojects)提供了详细步骤和示例代码。
|
关系型数据库 MySQL 数据库
InnoDB 的 MVCC 实现原理
InnoDB 的 MVCC 实现原理
221 0
|
网络协议 安全 网络性能优化
HTTP、HTTPS和TCP的特点和三者的区别
TCP提供连接、可靠性、流量和拥塞控制,HTTP基于请求-响应模型且无连接、无状态,HTTPS则通过数字证书确保服务器身份验证和加密通信。
|
JSON 机器人 Go
go接收alertmanager告警并发送钉钉
go接收alertmanager告警并发送钉钉
277 0
|
监控 Shell 开发工具
Debian安装与基本使用:详细指南及常见问题解析
【4月更文挑战第13天】本文档介绍了Debian的安装步骤、基本使用、问题解析及进阶技巧。首先,安装Debian涉及下载ISO镜像,制作启动介质,设置BIOS,然后进行安装过程,包括选择语言、分区、网络配置、软件包选择和用户账户设置。安装完成后,学会基本操作,如命令行使用、软件管理(apt)、系统更新和维护。遇到问题时,解决无线网络、分辨率、输入法和依赖问题。进阶技巧包括自定义Shell环境、使用虚拟化技术(Docker、LXC/LXD)、系统监控与性能调优,以及Git和自动化脚本的高级应用。通过学习这些技巧,可提升在Debian系统上的工作效率。
2224 0
|
SpringCloudAlibaba 算法 Java
Spring Boot项目如何实现分布式日志链路追踪
作为一名后端开发工程师,排查系统问题用得最多的手段之一就是查看系统日志,在当下主要的分布式集群环境中一般使用ELK(Elasticsearch , Logstash, Kibana)来统一收集日志,以便后续查看日志定位追踪相关问题。但是在并发情况下,大量的系统用户即多线程并发访问后端服务导致同一个请求的日志记录不再是连续相邻的,此时多个请求的日志是一起串行输出到文件中,所以我们筛选出指定请求的全部相关日志还是比较麻烦的,同时当后端异步处理功能逻辑以及微服务的下游服务调用日志追踪也有着相同的问题。
|
Linux 图形学 Windows
嵌入式课程实现Linux操作系统LVGL移植操作
嵌入式课程实现Linux操作系统LVGL移植操作