dubbo系列之@Service註解解析原理(四)

歡迎關注公衆號【sharedCode】致力於主流中間件的源碼分析, 能夠直接與我聯繫java

前言

前面幾篇文章,講的是調試環境搭建,配置解析讀取,本文講的是dubbo如何解析@service註解的,瞭解這些東西對於真正使用dubbo來講,沒有直接的東西,可是這個是我後面要寫的dubbo核心功能源碼解析的前提,先後連貫,這樣才能瞭解的更加清晰一點。spring

解析入口

@service註解解析入口有兩個地方,兩者是二選一的app

第一種

DubboAutoConfiguration 這個自動配置類中ide

@ConditionalOnMissingBean
@Bean(name = ReferenceAnnotationBeanPostProcessor.BEAN_NAME)
public ReferenceAnnotationBeanPostProcessor referenceAnnotationBeanPostProcessor() {
  return new ReferenceAnnotationBeanPostProcessor();
}
@ConditionalOnProperty(name = BASE_PACKAGES_PROPERTY_NAME)
@ConditionalOnClass(RelaxedPropertyResolver.class)
@Bean
public ServiceAnnotationBeanPostProcessor serviceAnnotationBeanPostProcessor(Environment environment) {
  RelaxedPropertyResolver resolver = new RelaxedPropertyResolver(environment);
  Set<String> packagesToScan = resolver.getProperty(BASE_PACKAGES_PROPERTY_NAME, Set.class, emptySet());
  return new ServiceAnnotationBeanPostProcessor(packagesToScan);
}

上面兩個配置的做用,在上文中已經講解過,此處再也不贅述源碼分析

第二種

@SpringBootApplication
@DubboComponentScan("com.dubbo.consumer.service")
public class ConsumerApplication {


    public static void main(String[] args) {
        SpringApplication.run(ConsumerApplication.class);
    }

}

請求頭上使用了@DubboComponentScan 註解,該註解是導入一個DubboComponentScanRegistrar這個類。post

@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 方法,該方法會實例化一些BeanDefinition進入spring容器ui

Override
  public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
  // 獲取掃描包路徑
  Set<String> packagesToScan = getPackagesToScan(importingClassMetadata);
  // 註冊@service解析的類
  registerServiceAnnotationBeanPostProcessor(packagesToScan, registry);
  // 註冊解析@Reference註解的bean
  registerReferenceAnnotationBeanPostProcessor(registry);

}

在咱們的調試例子中,使用的是在啓動類中添加註解進行@DubboComponentScan 啓動的,因此這裏就按照這個方式來,其實第一種和第二種的方式是差很少的,最終都是經過初始化ServiceAnnotationBeanPostProcessor 這個類來達到解析@Service 並生成bean的目的。 接着上面的代碼講,註冊解析@@service的方法是.net

registerServiceAnnotationBeanPostProcessor , 下面看一下這個方法。調試

private void registerServiceAnnotationBeanPostProcessor(Set<String> packagesToScan, BeanDefinitionRegistry registry) {
		// 構建ServiceAnnotationBeanPostProcessor的 BeanDefinitionBuilder
        BeanDefinitionBuilder builder = rootBeanDefinition(ServiceAnnotationBeanPostProcessor.class);
        builder.addConstructorArgValue(packagesToScan); // 掃描的包
        builder.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); 
        AbstractBeanDefinition beanDefinition = builder.getBeanDefinition(); 
  		// 建立BeanDefinition並註冊到容器中。
        BeanDefinitionReaderUtils.registerWithGeneratedName(beanDefinition, registry);

}

這個方法就是這麼簡單,有些朋友可能以爲,就這幾行代碼,就可以解析@Service註解了? 徹底沒有看到解析的邏輯代碼呢。其實主要的在於ServiceAnnotationBeanPostProcessor 這個類。code

ServiceAnnotationBeanPostProcessor

public class ServiceAnnotationBeanPostProcessor implements BeanDefinitionRegistryPostProcessor, EnvironmentAware,
        ResourceLoaderAware, BeanClassLoaderAware {
  // 代碼省略
}

首先咱們看一下這個類他實現的接口,實現了BeanDefinitionRegistryPostProcessor, EnvironmentAware, ResourceLoaderAware, BeanClassLoaderAware這四個接口, 主要看BeanDefinitionRegistryPostProcessor這個接口,看一下下面的官方解釋

**官方解釋 **

容許在正常的BeanFactoryPostProcessor檢測開始以前註冊更多的自定義bean。特別是,BeanDefinitionRegistryPostProcessor
能夠註冊更多的bean定義,而後定義BeanFactoryPostProcessor實例。也就是說能夠藉此方法實現自定義的bean,經過重寫postProcessBeanDefinitionRegistry方法來自定義bean

經過看上面的解釋,咱們直接找到postProcessBeanDefinitionRegistry方法

@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {

  // 獲取掃描包,掃描包能夠是多個,因此這裏使用了Set集合
  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!");
    }
  }

}

registerServiceBeans

private void registerServiceBeans(Set<String> packagesToScan, BeanDefinitionRegistry registry) {
		// 定義掃描對象,該類繼承了ClassPathBeanDefinitionScanner類
        DubboClassPathBeanDefinitionScanner scanner =
                new DubboClassPathBeanDefinitionScanner(registry, environment, resourceLoader);
		// beanName解析器
        BeanNameGenerator beanNameGenerator = resolveBeanNameGenerator(registry);

        scanner.setBeanNameGenerator(beanNameGenerator);
		// 這行代碼很重要,添加了過濾器, 一個註解過濾器,用來過濾出來寫了@Service註解的對象
        scanner.addIncludeFilter(new AnnotationTypeFilter(Service.class));
		// 掃描正式開始,遍歷包
        for (String packageToScan : packagesToScan) {

            // Registers @Service Bean first
            scanner.scan(packageToScan);

            // 開始查找添加了@Service註解的類
            Set<BeanDefinitionHolder> beanDefinitionHolders =
                    findServiceBeanDefinitionHolders(scanner, packageToScan, registry, beanNameGenerator);
			// 找到了則不爲空
            if (!CollectionUtils.isEmpty(beanDefinitionHolders)) {
				// 循環。
                for (BeanDefinitionHolder beanDefinitionHolder : beanDefinitionHolders) {
                    // 註冊serviceBean
                    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 + "]");
                }

            }

        }

    }

上面的代碼,主要做用就是經過掃描過濾器,掃描包中添加了@Service註解的類。最後獲得BeanDefinitionHolder對象,調用registerServiceBean來註冊ServiceBean

private void registerServiceBean(BeanDefinitionHolder beanDefinitionHolder, BeanDefinitionRegistry registry,
                                     DubboClassPathBeanDefinitionScanner scanner) {

  		// 服務接口類對象
        Class<?> beanClass = resolveClass(beanDefinitionHolder);
		// 找到@service註解
        Service service = findAnnotation(beanClass, Service.class);
		// 接口服務的實現類對象
        Class<?> interfaceClass = resolveServiceInterfaceClass(beanClass, service);
		// 獲得bean的名稱
        String annotatedServiceBeanName = beanDefinitionHolder.getBeanName();
		// 構建ServiceBean對象的BeanDefinition,經過Service註解對象,以及接口服務的實現類生成ServiceBean
        AbstractBeanDefinition serviceBeanDefinition =
                buildServiceBeanDefinition(service, interfaceClass, annotatedServiceBeanName);

        // 構建ServuceBean的名稱
        String beanName = generateServiceBeanName(service, interfaceClass, annotatedServiceBeanName);
		
  		// 校驗Bean是否重複
        if (scanner.checkCandidate(beanName, serviceBeanDefinition)) { // check duplicated candidate bean
          	// 調用BeanDefinitionRegistry註冊。
            registry.registerBeanDefinition(beanName, serviceBeanDefinition); 

            if (logger.isInfoEnabled()) {
                logger.warn("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這個方法用來構建ServiceBean對象,每一個暴露出的服務,最終都會構建成一個ServiceBean,

private AbstractBeanDefinition buildServiceBeanDefinition(Service service, Class<?> interfaceClass,
                                                              String annotatedServiceBeanName) {
		// 生成ServiceBean對象BeanDefinitionBuilder
        BeanDefinitionBuilder builder = rootBeanDefinition(ServiceBean.class);
		// 獲取beanDefinition
        AbstractBeanDefinition beanDefinition = builder.getBeanDefinition();
		// 屬性集合
        MutablePropertyValues propertyValues = beanDefinition.getPropertyValues();
		// 忽略的屬性,指的是AnnotationPropertyValuesAdapter中,不把如下屬性放到PropertyValues中去
        String[] ignoreAttributeNames = of("provider", "monitor", "application", "module", "registry", "protocol", "interface");
		// 
        propertyValues.addPropertyValues(new AnnotationPropertyValuesAdapter(service, environment, ignoreAttributeNames));

        // 設置ref屬性
        addPropertyReference(builder, "ref", annotatedServiceBeanName);
        // 服務的接口
        builder.addPropertyValue("interface", interfaceClass.getName());

        /**
         * 獲取註解中的provider屬性
         */
        String providerConfigBeanName = service.provider();
        if (StringUtils.hasText(providerConfigBeanName)) {
            addPropertyReference(builder, "provider", providerConfigBeanName);
        }

        /**
         * 獲取註解中的monitor屬性
         */
        String monitorConfigBeanName = service.monitor();
        if (StringUtils.hasText(monitorConfigBeanName)) {
            addPropertyReference(builder, "monitor", monitorConfigBeanName);
        }

        /**
         * 獲取註解中的application屬性
         */
        String applicationConfigBeanName = service.application();
        if (StringUtils.hasText(applicationConfigBeanName)) {
            addPropertyReference(builder, "application", applicationConfigBeanName);
        }

        /**
         * 獲取註解中的模塊屬性
         */
        String moduleConfigBeanName = service.module();
        if (StringUtils.hasText(moduleConfigBeanName)) {
            addPropertyReference(builder, "module", moduleConfigBeanName);
        }


        /**
         * 獲取註解中的註冊中心屬性
         */
        String[] registryConfigBeanNames = service.registry();

        List<RuntimeBeanReference> registryRuntimeBeanReferences = toRuntimeBeanReferences(registryConfigBeanNames);

        if (!registryRuntimeBeanReferences.isEmpty()) {
            builder.addPropertyValue("registries", registryRuntimeBeanReferences);
        }

        /**
         * 獲取註解中的協議屬性
         */
        String[] protocolConfigBeanNames = service.protocol();

        List<RuntimeBeanReference> protocolRuntimeBeanReferences = toRuntimeBeanReferences(protocolConfigBeanNames);

        if (!protocolRuntimeBeanReferences.isEmpty()) {
            builder.addPropertyValue("protocols", protocolRuntimeBeanReferences);
        }

        return builder.getBeanDefinition();

    }

最終dubbo解析出了ServiceBean對象的beandefinition放入了spring的容器。ServiceBean對於每一個暴露的服務來講很重要,每一個暴露的服務都擁有一個ServiceBean,這個類裏面包含了服務發佈,服務下線等操做,算是一個很核心的類,後面會講到。

歡迎關注公衆號【sharedCode】致力於主流中間件的源碼分析, 能夠直接與我聯繫

相關文章
相關標籤/搜索