dubbo源码阅读-配置(三)之属性配置

示例代码

public class Provider {
    /**
     * In order to make sure multicast registry works, need to specify '-Djava.net.preferIPv4Stack=true' before
     * launch the application
     */
    public static void main(String[] args) throws Exception {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ProviderConfiguration.class);
        context.start();
        System.in.read();
    }

    @Configuration
    /**
     * <1>内部包含import注解 作为初始化
     * 快速入门:https://www.cnblogs.com/yichunguo/p/12122598.html
     */
    @EnableDubbo(scanBasePackages = "provider") //
    @PropertySource("classpath:dubbo-provider.properties") // <2>
    static class ProviderConfiguration {
    }
}

dubbo-provider配置

dubbo.application.name=soa-promotion-provider
dubbo.registry.address=127.0.0.1:9080
dubbo.registry.check=false
dubbo.protocol.name=dubbo
dubbo.protocol.port=23888
dubbo.protocol.threads=500
dubbo.protocol.dispatcher=message
dubbo.provider.delay=-1
dubbo.provider.retries=false

配置之后就会在容器里面创建对应的config对象

<1>EnableDubbo

@Target({ElementType.TYPE})//只能打在类上
@Retention(RetentionPolicy.RUNTIME)//保留到运行时
@Inherited
@Documented
@EnableDubboConfig//<2>@Import注解位置
@DubboComponentScan
public @interface EnableDubbo {
    /**
     * spring的注解 后续可以通过spring api获取DubboComponentScan 拿到DubboComponentScan设置的值
     * @return
     */
    @AliasFor(annotation = DubboComponentScan.class, attribute = "basePackages")
    String[] scanBasePackages() default {};

    /**
     * DubboComponentScan的合并注解
     * @return
     */
    @AliasFor(annotation = DubboComponentScan.class, attribute = "basePackageClasses")
    Class<?>[] scanBasePackageClasses() default {};
    /**
     * DubboComponentScan的合并注解
     * @return
     */
    @AliasFor(annotation = EnableDubboConfig.class, attribute = "multiple")
    boolean multipleConfig() default true;

}

<2>EnableDubboConfig

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
@Import(DubboConfigConfigurationRegistrar.class)//<3>初始化切入点
public @interface EnableDubboConfig {

    /**
     * 是否支持多配置
     * dubbo.registrys.beaname1.address=192.168.0.1:1111
     * dubbo.registrys.beaname2.address=192.168.0.1:1111
     * @return
     */
    boolean multiple() default true;

}

@Import快速入门:链接 

可以理解为当 bean被spring容器初始化则@Import则会被调用

DubboConfigConfigurationRegistrar

<3>DubboConfigConfigurationRegistrar

org.springframework.context.annotation.ImportBeanDefinitionRegistrar

public class DubboConfigConfigurationRegistrar implements ImportBeanDefinitionRegistrar {

    /**
     *
     * @param importingClassMetadata 包含@Import注解类的其他注解信息
     * @param registry 通过他可以像容器注入bean
     */
    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {

        /**
         * 获取EnableDubboConfig 注解信息
         */
        AnnotationAttributes attributes = AnnotationAttributes.fromMap(
                importingClassMetadata.getAnnotationAttributes(EnableDubboConfig.class.getName()));
        /**
         * 获取multiple 默认为true 表示是否支持多个config配置
         * 参考
         */
        boolean multiple = attributes.getBoolean("multiple");
        /**
         * 初始化单个配置config
         * <4>注意此类打了@Import注解 继续往下看
         */
        registerBeans(registry, DubboConfigConfiguration.Single.class);

        /**
         * <4>如果开启多个配置 则初始化多个配置的config
         * dubbo.applications.beanname.id=ddd
         * dubbo.registrys.beaname2.address=192.168.0.1:1111
         * dubbo.registrys.beaname2.address=192.168.0.1:2222
         */
        if (multiple) { // Since 2.6.6 https://github.com/apache/incubator-dubbo/issues/3193
            registerBeans(registry, DubboConfigConfiguration.Multiple.class);
        }
    }
}

<4>DubboConfigConfiguration

public class DubboConfigConfiguration {
    /**
     * <5>定义了单个配置 每个前缀对应的 类
     */
    @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)
    })
    public static class Single {

    }
    /**
     * <5>定义了多个配置每个前缀对应的类
     */
    @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)
    })
    public static class Multiple {

    }
}

<5>EnableDubboConfigBindings

/**
 * Multiple {@link EnableDubboConfigBinding} {@link Annotation}
 *
 * @since 2.5.8
 * @see EnableDubboConfigBinding
 */
@Target({ElementType.TYPE}) //注解限制打在的地方
@Retention(RetentionPolicy.RUNTIME) //注解保留时期 这里是保留到运行时
@Documented //标识被javadoc记录
@Import(DubboConfigBindingsRegistrar.class)//注意看<3>.4处会注册打上此注解的实例到容器 所以会触发Import <6>@Import 
public @interface EnableDubboConfigBindings {

    /**
     * The value of {@link EnableDubboConfigBindings}
     *
     * @return non-null
     */
    EnableDubboConfigBinding[] value();

}

DubboConfigBindingsRegistrar

<6>registerBeanDefinitions

com.alibaba.dubbo.config.spring.context.annotation.DubboConfigBindingsRegistrar#registerBeanDefinitions

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

        //获取EnableDubboConfigBindings注解实例
        AnnotationAttributes attributes = AnnotationAttributes.fromMap(
                importingClassMetadata.getAnnotationAttributes(EnableDubboConfigBindings.class.getName()));
        //获得values注解实例 EnableDubboConfigBinding
        AnnotationAttributes[] annotationAttributes = attributes.getAnnotationArray("value");
        DubboConfigBindingRegistrar registrar = new DubboConfigBindingRegistrar();
        registrar.setEnvironment(environment);
        //循环遍历EnableDubboConfigBinding配置<4>处 能够获取到各个前缀和class的映射关系
        for (AnnotationAttributes element : annotationAttributes) {
            //<7> 负责解析前缀和class映射关系
            registrar.registerBeanDefinitions(element, registry);

        }
    }

DubboConfigBindingRegistrar

<7>registerBeanDefinitions

com.alibaba.dubbo.config.spring.context.annotation.DubboConfigBindingRegistrar#registerBeanDefinitions

 protected void registerBeanDefinitions(AnnotationAttributes attributes, BeanDefinitionRegistry registry) {

        /***
         *   获得注解配置的前缀 比如
         *   dubbo.application
         *    environment.resolvePlaceholders是为了避免我们配置的占位符所以转换一下
         *    比如${applictionPrefix}.name=
         */
        String prefix = environment.resolvePlaceholders(attributes.getString("prefix"));

        /**
         * 获取对应的class 如前缀是dubbo.application class就是com.alibaba.dubbo.config.ApplicationConfig
         * 泛型<extends AbstractConfig>限制class必须继承AbstractConfig
         */
        Class<? extends AbstractConfig> configClass = attributes.getClass("type");

        /**
         * 是否是多个配置
         */
        boolean multiple = attributes.getBoolean("multiple");

        /**
         * <8>创建对应的config bean
         */
        registerDubboConfigBeans(prefix, configClass, multiple, registry);

    }

<8>registerDubboConfigBeans

private void registerDubboConfigBeans(String prefix,
                                          Class<? extends AbstractConfig> configClass,
                                          boolean multiple,
                                          BeanDefinitionRegistry registry) {

        //获得指定前缀的属性 如:dubbo.application.name=333  key=name value=333
        Map<String, Object> properties = getSubProperties(environment.getPropertySources(), prefix);

        if (CollectionUtils.isEmpty(properties)) {
            if (log.isDebugEnabled()) {
                log.debug("There is no property for binding to dubbo config class [" + configClass.getName()
                        + "] within prefix [" + prefix + "]");
            }
            return;
        }
        /**
         * 配置的mltiple为false取得配置文件配置的id作为beanName(id)
         * 如果没获取到则生成类全名称#index 叠加
         * multip是true则解析
         * dubbo.applications.beanname1.name=ffff
         * dubbo.applications.beanname2.namee=ffff2
         * 这个时候beanname1和beanname2会作为二beanid
         */
        Set<String> beanNames = multiple ? resolveMultipleBeanNames(properties) :
                Collections.singleton(resolveSingleBeanName(properties, configClass, registry));

        for (String beanName : beanNames) {

            /**
             * 这里并没有真正的初始化config对象,只是将bean的定义告诉容器 供容器初始化
             * 初始化后config各个属性都是空
             */
            registerDubboConfigBean(beanName, configClass, registry);

            /**
             * <8>初始化对应的DubboConfigBindingBeanPostProcessor 用于后面为将properties配置注入到对应的config
             */
            registerDubboConfigBindingBeanPostProcessor(prefix, beanName, multiple, registry);

        }
        //向容器创建NamePropertyDefaultValueDubboConfigBeanCustomizer,供DubboConfigBindingBeanPostProcessor使用
        registerDubboConfigBeanCustomizers(registry);

    }

 

上一篇:在 IDEA 中运行 Spark 程序报错:Multiple sources found for text.......please specify the fully qualified class


下一篇:基于Windows下处理Java错误:编码GBK的不可映射字符的解决方案