Dubbo2.7源碼詳解

来源:https://www.cnblogs.com/chafry/archive/2022/10/17/16795441.html
-Advertisement-
Play Games

Spring與Dubbo整合原理與源碼分析 【1】註解@EnableDubbo @Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Inherited @Documented @EnableDubboConfig // @ ...


Spring與Dubbo整合原理與源碼分析

  【1】註解@EnableDubbo

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
@EnableDubboConfig   // @EnableDubboConfig註解用來將properties文件中的配置項轉化為對應的Bean
@DubboComponentScan  // @DubboComponentScan註解用來掃描服務提供者和引用者(@Service與@Reference)
public @interface EnableDubbo {

    @AliasFor(annotation = DubboComponentScan.class, attribute = "basePackages")
    String[] scanBasePackages() default {};

    @AliasFor(annotation = DubboComponentScan.class, attribute = "basePackageClasses")
    Class<?>[] scanBasePackageClasses() default {};

    @AliasFor(annotation = EnableDubboConfig.class, attribute = "multiple")
    boolean multipleConfig() default true;

}

 

  【2】註解@EnableDubboConfig

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
@Import(DubboConfigConfigurationRegistrar.class)
public @interface EnableDubboConfig {

    boolean multiple() default true;
}

    1)DubboConfigConfigurationRegistrar類的作用

//因為實現了ImportBeanDefinitionRegistrar介面,spring容器就會實例化該類,並且調用其registerBeanDefinitions方法;
public class DubboConfigConfigurationRegistrar implements ImportBeanDefinitionRegistrar {
    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
        //執行DubboConfigConfigurationRegistrar;

        AnnotationAttributes attributes = AnnotationAttributes.fromMap(
                importingClassMetadata.getAnnotationAttributes(EnableDubboConfig.class.getName()));

        boolean multiple = attributes.getBoolean("multiple"); //預設值是true

        // Single Config Bindings
        registerBeans(registry, DubboConfigConfiguration.Single.class);

        if (multiple) { // Since 2.6.6 https://github.com/apache/dubbo/issues/3193
            registerBeans(registry, DubboConfigConfiguration.Multiple.class);
        }
    }
}

 

    2)registerBeans做了什麼

public static void registerBeans(BeanDefinitionRegistry registry, Class<?>... annotatedClasses) {
    if (ObjectUtils.isEmpty(annotatedClasses)) {
        return;
    }
    ...
    AnnotatedBeanDefinitionReader reader = new AnnotatedBeanDefinitionReader(registry);
    ...
    // 利用Spring中的AnnotatedBeanDefinitionReader來解析annotatedClasses
    // 會解析該類上的註解,然後進行處理
    reader.register(annotatedClasses);

}

 

    3)DubboConfigConfiguration類展示

public class DubboConfigConfiguration {

    /**
     * Single Dubbo {@link AbstractConfig Config} Bean Binding
     */
    @EnableDubboConfigBindings({
            @EnableDubboConfigBinding(prefix = "dubbo.application", type = ApplicationConfig.class),
            @EnableDubboConfigBinding(prefix = "dubbo.module", type = ModuleConfig.class),
            @EnableDubboConfigBinding(prefix = "dubbo.registry", type = RegistryConfig.class),
            @EnableDubboConfigBinding(prefix = "dubbo.protocol", type = ProtocolConfig.class),
            @EnableDubboConfigBinding(prefix = "dubbo.monitor", type = MonitorConfig.class),
            @EnableDubboConfigBinding(prefix = "dubbo.provider", type = ProviderConfig.class),
            @EnableDubboConfigBinding(prefix = "dubbo.consumer", type = ConsumerConfig.class),
            @EnableDubboConfigBinding(prefix = "dubbo.config-center", type = ConfigCenterBean.class),
            @EnableDubboConfigBinding(prefix = "dubbo.metadata-report", type = MetadataReportConfig.class),
            @EnableDubboConfigBinding(prefix = "dubbo.metrics", type = MetricsConfig.class)
    })
    public static class Single {}

    /**
     * Multiple Dubbo {@link AbstractConfig Config} Bean Binding
     */
    @EnableDubboConfigBindings({
            @EnableDubboConfigBinding(prefix = "dubbo.applications", type = ApplicationConfig.class, multiple = true),
            @EnableDubboConfigBinding(prefix = "dubbo.modules", type = ModuleConfig.class, multiple = true),
            @EnableDubboConfigBinding(prefix = "dubbo.registries", type = RegistryConfig.class, multiple = true),
            @EnableDubboConfigBinding(prefix = "dubbo.protocols", type = ProtocolConfig.class, multiple = true),
            @EnableDubboConfigBinding(prefix = "dubbo.monitors", type = MonitorConfig.class, multiple = true),
            @EnableDubboConfigBinding(prefix = "dubbo.providers", type = ProviderConfig.class, multiple = true),
            @EnableDubboConfigBinding(prefix = "dubbo.consumers", type = ConsumerConfig.class, multiple = true),
            @EnableDubboConfigBinding(prefix = "dubbo.config-centers", type = ConfigCenterBean.class, multiple = true),
            @EnableDubboConfigBinding(prefix = "dubbo.metadata-reports", type = MetadataReportConfig.class, multiple = true),
            @EnableDubboConfigBinding(prefix = "dubbo.metricses", type = MetricsConfig.class, multiple = true)
    })
    public static class Multiple {}
}

 

    4)那麼必然又會解析到@EnableDubboConfigBindings註解

//又是利用了實現了ImportBeanDefinitionRegistrar介面,在實例化該類會調用其registerBeanDefinitions方法;
public class DubboConfigBindingsRegistrar implements ImportBeanDefinitionRegistrar, EnvironmentAware {

    private ConfigurableEnvironment environment;

    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
        //執行DubboConfigBindingsRegistrar
        AnnotationAttributes attributes = AnnotationAttributes.fromMap(importingClassMetadata.getAnnotationAttributes(EnableDubboConfigBindings.class.getName()));

        // 拿到多個@EnableDubboConfigBinding註解
        AnnotationAttributes[] annotationAttributes = attributes.getAnnotationArray("value");

        DubboConfigBindingRegistrar registrar = new DubboConfigBindingRegistrar();
        //將環境變數註入
        registrar.setEnvironment(environment);

        for (AnnotationAttributes element : annotationAttributes) {
            // 逐個解析@EnableDubboConfigBinding註解,比如@EnableDubboConfigBinding(prefix = "dubbo.application", type = ApplicationConfig.class)
            registrar.registerBeanDefinitions(element, registry);
        }
    }

    @Override
    public void setEnvironment(Environment environment) {
        Assert.isInstanceOf(ConfigurableEnvironment.class, environment);
        this.environment = (ConfigurableEnvironment) environment;
    }

}

 

    5)registrar.registerBeanDefinitions方法的調用情況

public class DubboConfigBindingRegistrar implements ImportBeanDefinitionRegistrar, EnvironmentAware {

    private final Log log = LogFactory.getLog(getClass());

    private ConfigurableEnvironment environment;

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

        //執行DubboConfigBindingRegistrar

        AnnotationAttributes attributes = AnnotationAttributes.fromMap(importingClassMetadata.getAnnotationAttributes(EnableDubboConfigBinding.class.getName()));

        registerBeanDefinitions(attributes, registry);

    }

    protected void registerBeanDefinitions(AnnotationAttributes attributes, BeanDefinitionRegistry registry) {

        // prefix = "dubbo.application"
        String prefix = environment.resolvePlaceholders(attributes.getString("prefix"));

        // type = ApplicationConfig.class
        Class<? extends AbstractConfig> configClass = attributes.getClass("type");

        boolean multiple = attributes.getBoolean("multiple");
        //針對配置分別進行註冊成Bean對象,方法1
        registerDubboConfigBeans(prefix, configClass, multiple, registry);

    }

    //方法1,因為Single和Multiple都是走同一套邏輯,採用參數boolean multiple區分
    private void registerDubboConfigBeans(String prefix, Class<? extends AbstractConfig> configClass, boolean multiple, BeanDefinitionRegistry registry) {

        // 從properties文件中根據首碼拿對應的配置項,比如根據dubbo.application首碼,
        // 就可以拿到如下配置:
        // dubbo.application.name=dubbo-demo-provider-application
        // dubbo.application.logger=log4j
        Map<String, Object> properties = getSubProperties(environment.getPropertySources(), prefix);

        // 如果沒有相關的配置項,則不需要註冊BeanDefinition
        if (CollectionUtils.isEmpty(properties)) {
            if (log.isDebugEnabled()) {
                log.debug(...);
            }
            return;
        }

        // 根據配置項生成beanNames,為什麼會有多個?
        // 普通情況一個dubbo.application首碼對應一個ApplicationConfig類型的Bean
        // 特殊情況下(配置兩種協議),比如dubbo.protocols對應了:
        //        dubbo.protocols.p1.name=dubbo
        //        dubbo.protocols.p1.port=20880
        //        dubbo.protocols.p1.host=0.0.0.0

        //        dubbo.protocols.p2.name=http
        //        dubbo.protocols.p2.port=8082
        //        dubbo.protocols.p2.host=0.0.0.0
        // 那麼就需要對應兩個ProtocolConfig類型的Bean,那麼就需要兩個beanName:p1和p2

        // 這裡就是multiple為true或false的區別,名字的區別,根據multiple用來判斷是否從配置項中獲取beanName
        // 如果multiple為false,則看有沒有配置id屬性,如果沒有配置則自動生成一個beanName.
        Set<String> beanNames = multiple ? resolveMultipleBeanNames(properties) : Collections.singleton(resolveSingleBeanName(properties, configClass, registry));

        for (String beanName : beanNames) {
            // 為每個beanName,註冊一個空的BeanDefinition,方法2
            registerDubboConfigBean(beanName, configClass, registry);

            // 為每個bean註冊一個DubboConfigBindingBeanPostProcessor的Bean後置處理器,方法3
            //這裡存在的問題就是對應每一種配置都會產生對應的BeanPostProcessor,最多好像也就是10種左右
            //但其實一個就可以做的任務,拓展成多個貌似不太合理,結合處理邏輯都是同一套就很尷尬
            registerDubboConfigBindingBeanPostProcessor(prefix, beanName, multiple, registry);
        }

        // 註冊一個NamePropertyDefaultValueDubboConfigBeanCustomizer的bean
        registerDubboConfigBeanCustomizers(registry);

    }

    //方法2,為對應的配置生成一個beanDefinition,並註入到容器
    private void registerDubboConfigBean(String beanName, Class<? extends AbstractConfig> configClass,BeanDefinitionRegistry registry) {

        BeanDefinitionBuilder builder = rootBeanDefinition(configClass);

        AbstractBeanDefinition beanDefinition = builder.getBeanDefinition();

        registry.registerBeanDefinition(beanName, beanDefinition);   // ApplicatinoConfig對象

        if (log.isInfoEnabled()) {
            log.info("...); //日誌記錄
        }

    }

    //方法3
    private void registerDubboConfigBindingBeanPostProcessor(String prefix, String beanName, boolean multiple,BeanDefinitionRegistry registry) {

        // 註冊一個DubboConfigBindingBeanPostProcessor的Bean
        // 每個XxConfig的Bean對應一個DubboConfigBindingBeanPostProcessor的Bean
        // 比如,一個ApplicationConfig對應一個DubboConfigBindingBeanPostProcessor,
        // 一個ProtocolConfig也會對應一個DubboConfigBindingBeanPostProcessor
        // 在構造DubboConfigBindingBeanPostProcessor的時候會指定構造方法的值,這樣就可以區別開來了

        Class<?> processorClass = DubboConfigBindingBeanPostProcessor.class;

        BeanDefinitionBuilder builder = rootBeanDefinition(processorClass);

        // 真實的首碼,比如dubbo.registries.r2
        String actualPrefix = multiple ? normalizePrefix(prefix) + beanName : prefix;

        // 添加兩個構造方法參數值,所以會調用DubboConfigBindingBeanPostProcessor的兩個參數的構造方法
        builder.addConstructorArgValue(actualPrefix).addConstructorArgValue(beanName);

        AbstractBeanDefinition beanDefinition = builder.getBeanDefinition();

        beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);

        registerWithGeneratedName(beanDefinition, registry);

        if (log.isInfoEnabled()) {
            log.info(...);
        }

    }

    private void registerDubboConfigBeanCustomizers(BeanDefinitionRegistry registry) {
        registerInfrastructureBean(registry, BEAN_NAME, NamePropertyDefaultValueDubboConfigBeanCustomizer.class);
    }

    @Override
    public void setEnvironment(Environment environment) {
        Assert.isInstanceOf(ConfigurableEnvironment.class, environment);
        this.environment = (ConfigurableEnvironment) environment;

    }

    private Set<String> resolveMultipleBeanNames(Map<String, Object> properties) {
        Set<String> beanNames = new LinkedHashSet<String>();

        // 比如dubbo.protocols.p1.name=dubbo的propertyName為p1.name
        for (String propertyName : properties.keySet()) {

            // propertyName為p1.name
            int index = propertyName.indexOf(".");
            if (index > 0) {
                // 截取beanName名字為p1
                String beanName = propertyName.substring(0, index);
                beanNames.add(beanName);
            }
        }
        return beanNames;

    }

    private String resolveSingleBeanName(Map<String, Object> properties, Class<? extends AbstractConfig> configClass,BeanDefinitionRegistry registry) {

        // 配置了dubbo.application.id=appl,那麼appl就是beanName
        String beanName = (String) properties.get("id");
        // 如果beanName為null,則會進入if分支,由spring自動生成一個beanName,比如org.apache.dubbo.config.ApplicationConfig#0
        if (!StringUtils.hasText(beanName)) {
            BeanDefinitionBuilder builder = rootBeanDefinition(configClass);
            beanName = BeanDefinitionReaderUtils.generateBeanName(builder.getRawBeanDefinition(), registry);
        }

        return beanName;

    }

}

 

    6)單個DubboConfigBindingBeanPostProcessor的展示(刪減掉部分不怎麼用到的)

public class DubboConfigBindingBeanPostProcessor implements BeanPostProcessor, ApplicationContextAware, InitializingBean, BeanDefinitionRegistryPostProcessor {

    private final String prefix;

    private final String beanName;

    private DubboConfigBinder dubboConfigBinder;
    ....
    private List<DubboConfigBeanCustomizer> configBeanCustomizers = Collections.emptyList();
  ....
  
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {

        // 每個XxConfig對應一個BeanPostProcessor,所以每個DubboConfigBindingBeanPostProcessor只處理對應的beanName
        if (this.beanName.equals(beanName) && bean instanceof AbstractConfig) {

            AbstractConfig dubboConfig = (AbstractConfig) bean;
            // 從properties文件中獲取值,並設置到dubboConfig對象中
            bind(prefix, dubboConfig);

            // 設置dubboConfig對象的name屬性,設置為beanName
            customize(beanName, dubboConfig);

        }

        return bean;

    }

    private void bind(String prefix, AbstractConfig dubboConfig) {
        dubboConfigBinder.bind(prefix, dubboConfig);

        if (log.isInfoEnabled()) {
            log.info(...);
        }
    }

    private void customize(String beanName, AbstractConfig dubboConfig) {
        for (DubboConfigBeanCustomizer customizer : configBeanCustomizers) {
            customizer.customize(beanName, dubboConfig);
        }
    }

   ...
    @Override
    public void afterPropertiesSet() throws Exception {
        initDubboConfigBinder();        // 創建DefaultDubboConfigBinder
        initConfigBeanCustomizers();
    }

    private void initDubboConfigBinder() {
        if (dubboConfigBinder == null) {
            try {
                // 先從Spring容器中獲取DubboConfigBinder,預設獲取不到
                dubboConfigBinder = applicationContext.getBean(DubboConfigBinder.class);
            } catch (BeansException ignored) {
                if (log.isDebugEnabled()) {
                    log.debug("DubboConfigBinder Bean can't be found in ApplicationContext.");
                }
                // Use Default implementation
                // 生成一個預設的
                dubboConfigBinder = createDubboConfigBinder(applicationContext.getEnvironment());
            }
        }

        dubboConfigBinder.setIgnoreUnknownFields(ignoreUnknownFields);
        dubboConfigBinder.setIgnoreInvalidFields(ignoreInvalidFields);

    }

    private void initConfigBeanCustomizers() {
        // 得到之前創建了的NamePropertyDefaultValueDubboConfigBeanCustomizer
        Collection<DubboConfigBeanCustomizer> configBeanCustomizers = beansOfTypeIncludingAncestors(applicationContext, DubboConfigBeanCustomizer.class).values();

        this.configBeanCustomizers = new ArrayList<>(configBeanCustomizers);
        AnnotationAwareOrderComparator.sort(this.configBeanCustomizers);
    }
...
}

 

  【3】註解@DubboComponentScan

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(DubboComponentScanRegistrar.class)
public @interface DubboComponentScan {

    String[] value() default {};

    String[] basePackages() default {};

    Class<?>[] basePackageClasses() default {};

}

 

    1)導入的DubboComponentScanRegistrar類做了什麼

/又是利用了實現了ImportBeanDefinitionRegistrar介面,在實例化該類會調用其registerBeanDefinitions方法;
public class DubboComponentScanRegistrar implements ImportBeanDefinitionRegistrar {

    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
        //執行DubboComponentScanRegistrar

        // 拿到DubboComponentScan註解所定義的包路徑,掃描該package下的類,識別這些類上
        Set<String> packagesToScan = getPackagesToScan(importingClassMetadata);

        // 註冊ServiceAnnotationBeanPostProcessor一個Bean
        // 實現了BeanDefinitionRegistryPostProcessor介面,所以在Spring啟動時會調用postProcessBeanDefinitionRegistry方法
        // 該方法會進行掃描,掃描@Service註解了的類,然後生成BeanDefinition(會生成兩個,一個普通的bean,一個ServiceBean),後續的Spring周期中會生成Bean
        // 在ServiceBean中會監聽ContextRefreshedEvent事件,一旦Spring啟動完後,就會進行服務導出
        registerServiceAnnotationBeanPostProcessor(packagesToScan, registry);

        // 註冊ReferenceAnnotationBeanPostProcessor
        // 實現了AnnotationInjectedBeanPostProcessor介面,繼而實現了InstantiationAwareBeanPostProcessorAdapter介面
        // 所以Spring在啟動時,在對屬性進行註入時會調用AnnotationInjectedBeanPostProcessor介面中的postProcessPropertyValues方法
        // 在這個過程中會按照@Refrence註解的信息去生成一個RefrenceBean對象
        registerReferenceAnnotationBeanPostProcessor(registry);

    }

    //核心方法1,註冊一個對@Service註解處理的 BeanDefinitionRegistryPostProcessor
    private void registerServiceAnnotationBeanPostProcessor(Set<String> packagesToScan, BeanDefinitionRegistry registry) {
        // 生成一個RootBeanDefinition,對應的beanClass為ServiceAnnotationBeanPostProcessor.class
        BeanDefinitionBuilder builder = rootBeanDefinition(ServiceAnnotationBeanPostProcessor.class);
        // 將包路徑作為在構造ServiceAnnotationBeanPostProcessor時調用構造方法時的傳入參數
        builder.addConstructorArgValue(packagesToScan);
        builder.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
        AbstractBeanDefinition beanDefinition = builder.getBeanDefinition();
        BeanDefinitionReaderUtils.registerWithGeneratedName(beanDefinition, registry);

    }

    //核心方法2,註冊一個對屬性賦值處理的AnnotationInjectedBeanPostProcessor且帶有ApplicationListener事件監聽功能
    private void registerReferenceAnnotationBeanPostProcessor(BeanDefinitionRegistry registry) {

        // Register @Reference Annotation Bean Processor
        // 註冊一個ReferenceAnnotationBeanPostProcessor做為bean,ReferenceAnnotationBeanPostProcessor是一個BeanPostProcessor
        BeanRegistrar.registerInfrastructureBean(registry,ReferenceAnnotationBeanPostProcessor.BEAN_NAME, ReferenceAnnotationBeanPostProcessor.class);

    }

    private Set<String> getPackagesToScan(AnnotationMetadata metadata) {
        AnnotationAttributes attributes = AnnotationAttributes.fromMap(
                metadata.getAnnotationAttributes(DubboComponentScan.class.getName()));
        String[] basePackages = attributes.getStringArray("basePackages");
        Class<?>[] basePackageClasses = attributes.getClassArray("basePackageClasses");
        String[] value = attributes.getStringArray("value");
        // Appends value array attributes
        Set<String> packagesToScan = new LinkedHashSet<String>(Arrays.asList(value));
        packagesToScan.addAll(Arrays.asList(basePackages));
        for (Class<?> basePackageClass : basePackageClasses) {
            packagesToScan.add(ClassUtils.getPackageName(basePackageClass));
        }
        if (packagesToScan.isEmpty()) {
            return Collections.singleton(ClassUtils.getPackageName(metadata.getClassName()));
        }
        return packagesToScan;
    }

}

 

  【4】掃描@Service註解,並且進行處理

    彙總說明:實際上便是通過處理器掃描@Service註解的類,生成兩個Bean【類對應的普通Bean,與Dubbo中要用到的ServiceBean】

    其中ServiceBean,是先根據註解上的信息填充對應的屬性,後採用環境變數中獲取配置的屬性,來完成屬性填充。

public class ServiceAnnotationBeanPostProcessor implements BeanDefinitionRegistryPostProcessor, EnvironmentAware,ResourceLoaderAware, BeanClassLoaderAware {

    ...
    //核心方法1
    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {

        Set<String> resolvedPackagesToScan = resolvePackagesToScan(packagesToScan);

        if (!CollectionUtils.isEmpty(resolvedPackagesToScan)) {
            // 掃描包,進行Bean註冊,核心方法2調用
            registerServiceBeans(resolvedPackagesToScan, registry);
        } else {
            if (logger.isWarnEnabled()) {
                logger.warn("packagesToScan is empty , ServiceBean registry will be ignored!");
            }
        }

    }


    //核心方法2
    private void registerServiceBeans(Set<String> packagesToScan, BeanDefinitionRegistry registry) {

        DubboClassPathBeanDefinitionScanner scanner = new DubboClassPathBeanDefinitionScanner(registry, environment, resourceLoader);

        BeanNameGenerator beanNameGenerator = resolveBeanNameGenerator(registry);

        scanner.setBeanNameGenerator(beanNameGenerator);

        // 掃描被Service註解標註的類
        scanner.addIncludeFilter(new AnnotationTypeFilter(Service.class));
        scanner.addIncludeFilter(new AnnotationTypeFilter(com.alibaba.dubbo.config.annotation.Service.class));

        for (String packageToScan : packagesToScan) {

            // Registers @Service Bean first
            // 掃描Dubbo自定義的@Service註解
            scanner.scan(packageToScan);

            // 查找被@Service註解的類的BeanDefinition(無論這個類有沒有被@ComponentScan註解標註了)
            Set<BeanDefinitionHolder> beanDefinitionHolders = findServiceBeanDefinitionHolders(scanner, packageToScan, registry, beanNameGenerator);

            if (!CollectionUtils.isEmpty(beanDefinitionHolders)) {

                // 掃描到BeanDefinition開始處理它,核心方法3的調用
                for (BeanDefinitionHolder beanDefinitionHolder : beanDefinitionHolders) {
                    registerServiceBean(beanDefinitionHolder, registry, scanner);
                }

                if (logger.isInfoEnabled()) { logger.info(b...); }
            } else {
                if (logger.isWarnEnabled()) { logger.warn(...); }
            }

        }

    }

    //核心方法3
    private void registerServiceBean(BeanDefinitionHolder beanDefinitionHolder, BeanDefinitionRegistry registry, DubboClassPathBeanDefinitionScanner scanner) {
        // 處理掃描到的每一個BeanDefinition
        // 1. 得到@Service註解上所配置的參數
        // 2. 根據每一個BeanDefinition會再額外的生成一個ServiceBean
        // 3. 對於每一個被@Service註解的類(服務的實現類),會生成兩個Bean,一個服務實現類對應的Bean(普通Bean,和@Component一樣),一個ServiceBean(Dubbo中要用到的Bean,因為在ServiceBean中包括了很的Config)

        // 具體的服務實現類
        Class<?> beanClass = resolveClass(beanDefinitionHolder);
        // @Service可以對服務進行各種配置
        Annotation service = findServiceAnnotation(beanClass);

        AnnotationAttributes serviceAnnotationAttributes = getAnnotationAttributes(service, false, false);

        // 服務實現類對應的介面
        Class<?> interfaceClass = resolveServiceInterfaceClass(serviceAnnotationAttributes, beanClass);
        // 服務實現類對應的bean的名字,比如:demoServiceImpl
        String annotatedServiceBeanName = beanDefinitionHolder.getBeanName();

        // 生成一個ServiceBean,核心方法4的調用
        AbstractBeanDefinition serviceBeanDefinition = buildServiceBeanDefinition(service, serviceAnnotationAttributes, interfaceClass, annotatedServiceBeanName);

        // ServiceBean Bean name   ServiceBean表示服務,我們要使用一個服務應該拿ServiceBean
        String beanName = generateServiceBeanName(serviceAnnotationAttributes, interfaceClass);

        if (scanner.checkCandidate(beanName, serviceBeanDefinition)) { // check duplicated candidate bean

            // 把ServiceBean註冊進去,對應的beanName為ServiceBean:org.apache.dubbo.demo.DemoService
            registry.registerBeanDefinition(beanName, serviceBeanDefinition);

            if (logger.isInfoEnabled()) { logger.info(..); }
        } else {
            if (logger.isWarnEnabled()) { logger.warn(...); }
        }
    }

...

    //核心方法4
    private AbstractBeanDefinition buildServiceBeanDefinition(Annotation serviceAnnotation,AnnotationAttributes serviceAnnotationAttributes,Class<?> interfaceClass,String annotatedServiceBeanName) {
        // 生成一個ServiceBean對應的BeanDefinition
        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");

        // 把serviceAnnotation中的參數值賦值給ServiceBean的屬性
        // 如:@Service(test = "test") 
        propertyValues.addPropertyValues(new AnnotationPropertyValuesAdapter(serviceAnnotation, environment, ignoreAttributeNames));

        // References "ref" property to annotated-@Service Bean
        // 如:@Service(protocol = "P1"),這種就是要根據對應的值找到對應的P1的config對象裡面的值
        // ref屬性賦值為另外一個bean, 對應的就是被@Service註解的服務實現類對應的bean
        addPropertyReference(builder, "ref", annotatedServiceBeanName);

        // Set interface
        builder.addPropertyValue("interface", interfaceClass.getName());
        // Convert parameters into map
        builder.addPropertyValue("parameters", convertParameters(serviceAnnotationAttributes.getStringArray("parameters")));

        // 配置了methods屬性,則給ServiceBean對應的methods屬性賦值
        // Add methods parameters
        List<MethodConfig> methodConfigs = convertMethodConfigs(serviceAnnotationAttributes.get("methods"));
        if (!methodConfigs.isEmpty()) {
            builder.addPropertyValue("methods", methodConfigs);
        }

        /**
         * Add {@link org.apache.dubbo.config.ProviderConfig} Bean reference
         */
        String providerConfigBeanName = serviceAnnotationAttributes.getString("provider");
        if (StringUtils.hasText(providerConfigBeanName)) {
            addPropertyReference(builder, "provider", providerConfigBeanName);
        }

        /**
         * Add {@link org.apache.dubbo.config.MonitorConfig} Bean reference
         */
        String monitorConfigBeanName = serviceAnnotationAttributes.getString("monitor");
        if (StringUtils.hasText(monitorConfigBeanName)) {
            addPropertyReference(builder, "monitor", monitorConfigBeanName);
        }

        /**
         * Add {@link org.apache.dubbo.config.ApplicationConfig} Bean reference
         */
        String applicationConfigBeanName = serviceAnnotationAttributes.getString("application");
        if (StringUtils.hasText(applicationConfigBeanName)) {
            addPropertyReference(builder, "application", applicationConfigBeanName);
        }

        /**
         * Add {@link org.apache.dubbo.config.ModuleConfig} Bean reference
         */
        String moduleConfigBeanName = serviceAnnotationAttributes.getString("module");
        if (StringUtils.hasText(moduleConfigBeanName)

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 第二期 · 使用 Vue 3.1 + TypeScript + Router + Tailwind.css 仿 itch.io 平臺主頁。 我的主題 HapiGames 是仿 itch.io 的 indie game hosting marketplace。 效果圖 代碼倉庫 alicepolice ...
  • 這裡給大家分享我在網上總結出來的一些知識,希望對大家有所幫助 背景 昨天在看一道筆試題的時候本以為很簡單,但是結果不是我想象的那樣,直接上筆試題。 const array = new Array(5).map((item) => { return item = { name: '1' } }); c ...
  • 轉眼回長沙快2年了,圖書本在去年就已經完稿,因為疫情,一直耽擱了,直到這個月才出版!疫情之下,眾生皆苦!感覺每天都是吃飯、睡覺、上班、做核酸! 圖書介紹 為了緊跟技術潮流,該書聚焦於當下火的Vue3和TypeScript及其相關技術,這些知識是面試Vue方向前端崗位時必須掌握的內容。該書站在初學者的 ...
  • 我們知道,用戶體驗是 Web 產品最為重要的部分。儘可能減少首屏載入時間,更為流暢地展示用戶所需求的內容,會是用戶是否留存的關鍵因素。 而隨著現代 Web 業務可供用戶的交互行為越來越多,前端項目的複雜度越來越高,每個頁面的渲染時間也必然越來越長,這就導致了用戶的體驗不佳,用戶的操作變慢。 為此,前 ...
  • 一篇文章帶你瞭解網頁框架——Vue簡單入門 這篇文章將會介紹我們前端入門級別的框架——Vue的簡單使用 如果你以後想從事後端程式員,又想要稍微瞭解前端框架知識,那麼這篇文章或許可以給你帶來幫助 溫馨提醒:在學習該文章前,請先學習HTML,CSS,JavaScript,Ajax等前端知識 Vue基礎 ...
  • 函數式編程是一種思維模式。該使用什麼樣的方式去解決你的問題?就像你不想去破解一個代碼塊完整性(內聚),那麼你可以加入一個切麵,去影響該代碼塊的執行結果。以函數方式思考。對於一個業務邏輯,如果以函數的角度思考,那麼可以抽離出若幹的函數進行處理,而非亂糟糟的零散的代碼 ...
  • Windows 2008 Server上FTP伺服器安裝 FTP服務端安裝 首先需要一個windows server2008 的虛擬機,作為服務端,安裝FTP伺服器。 遠程連接桌面(安裝了VMware Tool了的可以直接跳過該步) 如果虛擬機沒有安裝VMware Tool無法直接將安裝配置文件拖入 ...
  • Minifilter 是一種文件過濾驅動,該驅動簡稱為微過濾驅動,相對於傳統的`sfilter`文件過濾驅動來說,微過濾驅動編寫時更簡單,其不需要考慮底層RIP如何派發且無需要考慮相容性問題,微過濾驅動使用過濾管理器`FilterManager`提供介面,由於提供了管理結構以及一系列管理API函數,... ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...