CoderLi

V1

2022/04/02阅读:15主题:兰青

服务注册流程分析01

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

@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.classargs);
        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 BeanDefinitionRegistryPostProcessorEnvironmentAware,
        ResourceLoaderAwareBeanClassLoaderAware 
{

发现其继承了不少接口、其中 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, falsefalse);

    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 中。

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

分类:

后端

标签:

后端

作者介绍

CoderLi
V1