示例代码
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); }